diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a94b43d34e0..0d34fdb6bad6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,10 +47,10 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - - name: JDK 21 + - name: JDK 25 uses: actions/setup-java@v4 with: - java-version: 21 + java-version: 25 distribution: 'zulu' - name: Setup Gradle diff --git a/build-data/paper.at b/build-data/paper.at index 3fd1ec2ceb0f..9c8788ce2b74 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -32,7 +32,7 @@ public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket z public net.minecraft.network.syncher.SynchedEntityData getItem(Lnet/minecraft/network/syncher/EntityDataAccessor;)Lnet/minecraft/network/syncher/SynchedEntityData$DataItem; public net.minecraft.resources.RegistryOps lookupProvider public net.minecraft.resources.RegistryOps$HolderLookupAdapter -public net.minecraft.server.Main forceUpgrade(Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lnet/minecraft/world/level/storage/WorldData;Lcom/mojang/datafixers/DataFixer;ZLjava/util/function/BooleanSupplier;Lnet/minecraft/core/RegistryAccess;Z)V +public net.minecraft.server.Main forceUpgrade(Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lcom/mojang/datafixers/DataFixer;ZLjava/util/function/BooleanSupplier;Lnet/minecraft/core/RegistryAccess;Z)V public net.minecraft.server.MinecraftServer LOGGER public net.minecraft.server.MinecraftServer doRunTask(Lnet/minecraft/server/TickTask;)V public net.minecraft.server.MinecraftServer executor @@ -41,11 +41,13 @@ public net.minecraft.server.MinecraftServer playerDataStorage public net.minecraft.server.MinecraftServer resources public net.minecraft.server.MinecraftServer serverThread public net.minecraft.server.MinecraftServer$ReloadableResources +public net.minecraft.server.MinecraftServer$ReloadableResources (Lnet/minecraft/server/packs/resources/CloseableResourceManager;Lnet/minecraft/server/ReloadableServerResources;)V public net.minecraft.server.RegistryLayer STATIC_ACCESS public net.minecraft.server.ReloadableServerResources public net.minecraft.server.ServerAdvancementManager advancements public net.minecraft.server.Services USERID_CACHE_FILE public net.minecraft.server.dedicated.DedicatedServerProperties$WorldDimensionData +public net.minecraft.server.dedicated.DedicatedServerProperties$WorldDimensionData (Lcom/google/gson/JsonObject;Ljava/lang/String;)V public net.minecraft.server.dedicated.Settings getStringRaw(Ljava/lang/String;)Ljava/lang/String; public net.minecraft.server.dedicated.Settings properties public net.minecraft.server.level.ChunkHolder oldTicketLevel @@ -96,6 +98,7 @@ public net.minecraft.server.level.ServerPlayer setShoulderEntityRight(Lnet/minec public net.minecraft.server.level.ServerPlayer triggerDimensionChangeTriggers(Lnet/minecraft/server/level/ServerLevel;)V public net.minecraft.server.level.ServerPlayer wardenSpawnTracker public net.minecraft.server.level.ServerPlayer$RespawnPosAngle +public net.minecraft.server.level.ServerPlayer$RespawnPosAngle (Lnet/minecraft/world/phys/Vec3;FF)V public net.minecraft.server.level.ServerPlayerGameMode level public net.minecraft.server.network.ServerConfigurationPacketListenerImpl clientInformation public net.minecraft.server.network.ServerConfigurationPacketListenerImpl currentTask @@ -136,8 +139,10 @@ public net.minecraft.world.damagesource.CombatTracker takingDamage public net.minecraft.world.damagesource.DamageSource (Lnet/minecraft/core/Holder;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;)V public net.minecraft.world.effect.MobEffect attributeModifiers public net.minecraft.world.effect.MobEffect$AttributeTemplate +public net.minecraft.world.effect.MobEffect$AttributeTemplate (Lnet/minecraft/resources/Identifier;DLnet/minecraft/world/entity/ai/attributes/AttributeModifier$Operation;)V public net.minecraft.world.effect.MobEffectInstance hiddenEffect public net.minecraft.world.effect.MobEffectInstance isShorterDurationThan(Lnet/minecraft/world/effect/MobEffectInstance;)Z +public net.minecraft.world.entity.AgeableMob setAgeLocked(Z)V public net.minecraft.world.entity.AreaEffectCloud durationOnUse public net.minecraft.world.entity.AreaEffectCloud owner public net.minecraft.world.entity.AreaEffectCloud potionContents @@ -218,6 +223,7 @@ public net.minecraft.world.entity.Interaction setHeight(F)V public net.minecraft.world.entity.Interaction setResponse(Z)V public net.minecraft.world.entity.Interaction setWidth(F)V public net.minecraft.world.entity.Interaction$PlayerAction +public net.minecraft.world.entity.Interaction$PlayerAction (Ljava/util/UUID;J)V public net.minecraft.world.entity.ItemBasedSteering boostTime public net.minecraft.world.entity.ItemBasedSteering boostTimeTotal()I public net.minecraft.world.entity.ItemBasedSteering boosting @@ -249,6 +255,7 @@ public net.minecraft.world.entity.Mob getAmbientSound()Lnet/minecraft/sounds/Sou public net.minecraft.world.entity.Mob isSunBurnTick()Z public net.minecraft.world.entity.Mob lootTable public net.minecraft.world.entity.Mob lootTableSeed +public net.minecraft.world.entity.Mob persistenceRequired public net.minecraft.world.entity.OminousItemSpawner setItem(Lnet/minecraft/world/item/ItemStack;)V public net.minecraft.world.entity.OminousItemSpawner spawnItemAfterTicks public net.minecraft.world.entity.ai.attributes.Attribute sentiment @@ -276,6 +283,10 @@ public net.minecraft.world.entity.animal.bee.Bee setRolling(Z)V public net.minecraft.world.entity.animal.bee.Bee stayOutOfHiveCountdown public net.minecraft.world.entity.animal.bee.Bee ticksWithoutNectarSinceExitingHive public net.minecraft.world.entity.animal.bee.Bee timeSinceSting +public net.minecraft.world.entity.animal.chicken.Chicken getSoundVariant()Lnet/minecraft/core/Holder; +public net.minecraft.world.entity.animal.chicken.Chicken setSoundVariant(Lnet/minecraft/core/Holder;)V +public net.minecraft.world.entity.animal.cow.Cow getSoundVariant()Lnet/minecraft/core/Holder; +public net.minecraft.world.entity.animal.cow.Cow setSoundVariant(Lnet/minecraft/core/Holder;)V public net.minecraft.world.entity.animal.cow.MushroomCow setVariant(Lnet/minecraft/world/entity/animal/cow/MushroomCow$Variant;)V public net.minecraft.world.entity.animal.cow.MushroomCow stewEffects public net.minecraft.world.entity.animal.dolphin.Dolphin treasurePos @@ -285,9 +296,11 @@ public net.minecraft.world.entity.animal.equine.AbstractHorse owner public net.minecraft.world.entity.animal.equine.Horse setVariantAndMarkings(Lnet/minecraft/world/entity/animal/equine/Variant;Lnet/minecraft/world/entity/animal/equine/Markings;)V public net.minecraft.world.entity.animal.equine.Llama setVariant(Lnet/minecraft/world/entity/animal/equine/Llama$Variant;)V public net.minecraft.world.entity.animal.equine.SkeletonHorse trapTime +public net.minecraft.world.entity.animal.feline.Cat getSoundVariant()Lnet/minecraft/core/Holder; public net.minecraft.world.entity.animal.feline.Cat isRelaxStateOne()Z public net.minecraft.world.entity.animal.feline.Cat setCollarColor(Lnet/minecraft/world/item/DyeColor;)V public net.minecraft.world.entity.animal.feline.Cat setRelaxStateOne(Z)V +public net.minecraft.world.entity.animal.feline.Cat setSoundVariant(Lnet/minecraft/core/Holder;)V public net.minecraft.world.entity.animal.feline.Cat setVariant(Lnet/minecraft/core/Holder;)V public net.minecraft.world.entity.animal.feline.Ocelot isTrusting()Z public net.minecraft.world.entity.animal.feline.Ocelot setTrusting(Z)V @@ -311,6 +324,8 @@ public net.minecraft.world.entity.animal.nautilus.AbstractNautilus inventory public net.minecraft.world.entity.animal.panda.Panda getEatCounter()I public net.minecraft.world.entity.animal.panda.Panda setEatCounter(I)V public net.minecraft.world.entity.animal.parrot.Parrot setVariant(Lnet/minecraft/world/entity/animal/parrot/Parrot$Variant;)V +public net.minecraft.world.entity.animal.pig.Pig getSoundVariant()Lnet/minecraft/core/Holder; +public net.minecraft.world.entity.animal.pig.Pig setSoundVariant(Lnet/minecraft/core/Holder;)V public net.minecraft.world.entity.animal.pig.Pig setVariant(Lnet/minecraft/core/Holder;)V public net.minecraft.world.entity.animal.pig.Pig steering public net.minecraft.world.entity.animal.rabbit.Rabbit moreCarrotTicks @@ -534,20 +549,21 @@ public net.minecraft.world.inventory.Slot slot public net.minecraft.world.item.AdventureModePredicate predicates public net.minecraft.world.item.BucketItem content public net.minecraft.world.item.CrossbowItem FIREWORK_POWER -public net.minecraft.world.item.DebugStickItem handleInteraction(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/item/ItemStack;)Z +public net.minecraft.world.item.DebugStickItem handleInteraction(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/item/ItemStack;)Z public net.minecraft.world.item.ItemCooldowns cooldowns public net.minecraft.world.item.ItemCooldowns tickCount public net.minecraft.world.item.ItemCooldowns$CooldownInstance +public net.minecraft.world.item.ItemCooldowns$CooldownInstance (II)V public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG public net.minecraft.world.item.JukeboxSongPlayer song public net.minecraft.world.item.MapItem createNewSavedData(Lnet/minecraft/server/level/ServerLevel;IIIZZLnet/minecraft/resources/ResourceKey;)Lnet/minecraft/world/level/saveddata/maps/MapId; public net.minecraft.world.item.StandingAndWallBlockItem wallBlock -public net.minecraft.world.item.component.BundleContents$Mutable getMaxAmountToAdd(Lnet/minecraft/world/item/ItemStack;)I public net.minecraft.world.item.component.ItemContainerContents MAX_SIZE public net.minecraft.world.item.component.ItemContainerContents items public net.minecraft.world.item.component.ResolvableProfile unpack()Lcom/mojang/datafixers/util/Either; public net.minecraft.world.item.component.ResolvableProfile$Dynamic (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/world/entity/player/PlayerSkin$Patch;)V public net.minecraft.world.item.component.ResolvableProfile$Partial +public net.minecraft.world.item.component.ResolvableProfile$Partial (Ljava/util/Optional;Ljava/util/Optional;Lcom/mojang/authlib/properties/PropertyMap;)V public net.minecraft.world.item.component.ResolvableProfile$Partial MAP_CODEC public net.minecraft.world.item.component.ResolvableProfile$Static (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/world/entity/player/PlayerSkin$Patch;)V public net.minecraft.world.item.context.UseOnContext (Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/BlockHitResult;)V @@ -584,6 +600,7 @@ public net.minecraft.world.level.TicketStorage tickets public net.minecraft.world.level.biome.Biome climateSettings public net.minecraft.world.level.biome.Biome getTemperature(Lnet/minecraft/core/BlockPos;I)F public net.minecraft.world.level.biome.Biome$ClimateSettings +public net.minecraft.world.level.biome.Biome$ClimateSettings (ZFLnet/minecraft/world/level/biome/Biome$TemperatureModifier;F)V public net.minecraft.world.level.block.Block popExperience(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;I)V public net.minecraft.world.level.block.ChestBlock isBlockedChestByBlock(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z public net.minecraft.world.level.block.ComposterBlock$EmptyContainer @@ -699,20 +716,20 @@ public net.minecraft.world.level.chunk.status.ChunkStatusTasks postLoadProtoChun public net.minecraft.world.level.chunk.storage.EntityStorage entityDeserializerQueue public net.minecraft.world.level.chunk.storage.EntityStorage level public net.minecraft.world.level.chunk.storage.RegionFileStorage regionCache -public net.minecraft.world.level.dimension.end.EndDragonFight GATEWAY_COUNT -public net.minecraft.world.level.dimension.end.EndDragonFight dragonEvent -public net.minecraft.world.level.dimension.end.EndDragonFight dragonUUID -public net.minecraft.world.level.dimension.end.EndDragonFight findExitPortal()Lnet/minecraft/world/level/block/state/pattern/BlockPattern$BlockPatternMatch; -public net.minecraft.world.level.dimension.end.EndDragonFight gateways -public net.minecraft.world.level.dimension.end.EndDragonFight level -public net.minecraft.world.level.dimension.end.EndDragonFight portalLocation -public net.minecraft.world.level.dimension.end.EndDragonFight previouslyKilled -public net.minecraft.world.level.dimension.end.EndDragonFight respawnCrystals -public net.minecraft.world.level.dimension.end.EndDragonFight respawnDragon(Ljava/util/List;)V -public net.minecraft.world.level.dimension.end.EndDragonFight respawnStage -public net.minecraft.world.level.dimension.end.EndDragonFight setRespawnStage(Lnet/minecraft/world/level/dimension/end/DragonRespawnAnimation;)V -public net.minecraft.world.level.dimension.end.EndDragonFight spawnExitPortal(Z)V -public net.minecraft.world.level.dimension.end.EndDragonFight spawnNewGateway(Lnet/minecraft/core/BlockPos;)V +public net.minecraft.world.level.dimension.end.EnderDragonFight GATEWAY_COUNT +public net.minecraft.world.level.dimension.end.EnderDragonFight dragonEvent +public net.minecraft.world.level.dimension.end.EnderDragonFight dragonUUID +public net.minecraft.world.level.dimension.end.EnderDragonFight exitPortalLocation +public net.minecraft.world.level.dimension.end.EnderDragonFight findExitPortal()Lnet/minecraft/world/level/block/state/pattern/BlockPattern$BlockPatternMatch; +public net.minecraft.world.level.dimension.end.EnderDragonFight gateways +public net.minecraft.world.level.dimension.end.EnderDragonFight hasPreviouslyKilledDragon +public net.minecraft.world.level.dimension.end.EnderDragonFight level +public net.minecraft.world.level.dimension.end.EnderDragonFight respawnCrystals +public net.minecraft.world.level.dimension.end.EnderDragonFight respawnDragon(Ljava/util/List;)V +public net.minecraft.world.level.dimension.end.EnderDragonFight respawnStage +public net.minecraft.world.level.dimension.end.EnderDragonFight setRespawnStage(Lnet/minecraft/world/level/dimension/end/DragonRespawnStage;)V +public net.minecraft.world.level.dimension.end.EnderDragonFight spawnExitPortal(Z)V +public net.minecraft.world.level.dimension.end.EnderDragonFight spawnNewGateway(Lnet/minecraft/core/BlockPos;)V public net.minecraft.world.level.entity.PersistentEntitySectionManager ensureChunkQueuedForLoad(J)V public net.minecraft.world.level.entity.PersistentEntitySectionManager permanentStorage public net.minecraft.world.level.gamerules.GameRules rules @@ -728,6 +745,7 @@ public net.minecraft.world.level.levelgen.SurfaceRules$LazyCondition public net.minecraft.world.level.levelgen.SurfaceRules$LazyYCondition public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule public net.minecraft.world.level.levelgen.SurfaceRules$VerticalGradientConditionSource +public net.minecraft.world.level.levelgen.SurfaceRules$VerticalGradientConditionSource (Lnet/minecraft/resources/Identifier;Lnet/minecraft/world/level/levelgen/VerticalAnchor;Lnet/minecraft/world/level/levelgen/VerticalAnchor;)V public net.minecraft.world.level.levelgen.structure.StructurePiece SHAPE_CHECK_BLOCKS public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement exclusionZone public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement frequency @@ -736,10 +754,11 @@ public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement salt public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate entityInfoList public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate palettes -public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager loadFromGenerated(Lnet/minecraft/resources/Identifier;)Ljava/util/Optional; -public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager loadFromResource(Lnet/minecraft/resources/Identifier;)Ljava/util/Optional; -public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager readStructure(Ljava/io/InputStream;)Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate; +public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager resourceManagerSource public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager structureRepository +public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager tryLoad(Lnet/minecraft/resources/Identifier;)Ljava/util/Optional; +public net.minecraft.world.level.levelgen.structure.templatesystem.loader.TemplateSource readStructure(Ljava/io/InputStream;)Lnet/minecraft/nbt/CompoundTag; +public net.minecraft.world.level.levelgen.structure.templatesystem.loader.TemplateSource readStructure(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate; public net.minecraft.world.level.material.MapColor MATERIAL_COLORS public net.minecraft.world.level.pathfinder.Path nodes public net.minecraft.world.level.pathfinder.PathFinder nodeEvaluator @@ -748,10 +767,10 @@ public net.minecraft.world.level.saveddata.maps.MapItemSavedData carriedByPlayer public net.minecraft.world.level.saveddata.maps.MapItemSavedData decorations public net.minecraft.world.level.saveddata.maps.MapItemSavedData setColorsDirty(II)V public net.minecraft.world.level.saveddata.maps.MapItemSavedData setDecorationsDirty()V -public net.minecraft.world.level.storage.DimensionDataStorage cache public net.minecraft.world.level.storage.LevelStorageSource baseDir public net.minecraft.world.level.storage.LevelStorageSource$LevelStorageAccess levelDirectory public net.minecraft.world.level.storage.PrimaryLevelData settings +public net.minecraft.world.level.storage.SavedDataStorage cache public net.minecraft.world.level.storage.TagValueInput input public net.minecraft.world.scores.Objective displayName public net.minecraft.world.scores.criteria.ObjectiveCriteria CRITERIA_CACHE @@ -778,8 +797,6 @@ public-f net.minecraft.world.item.trading.MerchantOffer maxUses public-f net.minecraft.world.item.trading.MerchantOffer priceMultiplier public-f net.minecraft.world.item.trading.MerchantOffer rewardExp public-f net.minecraft.world.item.trading.MerchantOffer xp -public-f net.minecraft.world.level.LevelSettings hardcore -public-f net.minecraft.world.level.LevelSettings levelName public-f net.minecraft.world.level.block.ChestBlock MENU_PROVIDER_COMBINER public-f net.minecraft.world.level.block.entity.BannerBlockEntity baseColor public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData centerX diff --git a/build.gradle.kts b/build.gradle.kts index 6cfd415fd2f3..bf048db4da4e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent plugins { - id("io.papermc.paperweight.core") version "2.0.0-beta.19" apply false + id("io.papermc.paperweight.core") version "2.0.0-SNAPSHOT" apply false } subprojects { @@ -11,7 +11,7 @@ subprojects { extensions.configure { toolchain { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(25) } } } @@ -21,7 +21,7 @@ val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" subprojects { tasks.withType().configureEach { options.encoding = Charsets.UTF_8.name() - options.release = 21 + options.release = 25 options.isFork = true options.compilerArgs.addAll(listOf("-Xlint:-deprecation", "-Xlint:-removal")) } diff --git a/gradle.properties b/gradle.properties index 4516647f0989..7387810e8ded 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ group=io.papermc.paper -version=1.21.11-R0.1-SNAPSHOT -mcVersion=1.21.11 +version=26.1-R0.1-SNAPSHOT +mcVersion=26.1 # This is the current API version for use in (paper-)plugin.yml files # During snapshot cycles this should be the anticipated version of the release target -apiVersion=1.21.11 +apiVersion=26.1 # Set to true while updating Minecraft version -updatingMinecraft=false +updatingMinecraft=true org.gradle.configuration-cache=true org.gradle.caching=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125fe..d997cfc60f4c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bad7c2462f5a..dbc3ce4a040f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a0348..0262dcbd52b4 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/paper-api/build.gradle.kts b/paper-api/build.gradle.kts index 49b247877966..82d8a47657c6 100644 --- a/paper-api/build.gradle.kts +++ b/paper-api/build.gradle.kts @@ -82,13 +82,13 @@ dependencies { api("org.jspecify:jspecify:1.0.0") // Test dependencies - testImplementation("org.apache.commons:commons-lang3:3.17.0") - testImplementation("org.junit.jupiter:junit-jupiter:5.12.2") + testImplementation("org.apache.commons:commons-lang3:3.20.0") + testImplementation("org.junit.jupiter:junit-jupiter:6.0.3") testImplementation("org.hamcrest:hamcrest:2.2") - testImplementation("org.mockito:mockito-core:5.14.1") - testImplementation("org.ow2.asm:asm-tree:9.8") - mockitoAgent("org.mockito:mockito-core:5.14.1") { isTransitive = false } // configure mockito agent that is needed in newer java versions - testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testImplementation("org.mockito:mockito-core:5.22.0") + testImplementation("org.ow2.asm:asm-tree:9.9.1") + mockitoAgent("org.mockito:mockito-core:5.22.0") { isTransitive = false } // configure mockito agent that is needed in newer java versions + testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.0.3") } val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath() diff --git a/paper-api/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/paper-api/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java index 50f6443b5af0..f094d7ee906e 100644 --- a/paper-api/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +++ b/paper-api/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java @@ -130,7 +130,7 @@ public interface VanillaGoal extends Goal { GoalKey FLEE_SUN = create("flee_sun", Creature.class); - GoalKey FOLLOW_BOAT = create("follow_boat", Creature.class); + GoalKey FOLLOW_PLAYER_RIDDEN_ENTITY = create("follow_player_ridden_entity", Creature.class); GoalKey GOLEM_RANDOM_STROLL_IN_VILLAGE = create("golem_random_stroll_in_village", Creature.class); diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTypeKeys.java index c948b3f7b082..19df41713a1e 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTypeKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTypeKeys.java @@ -2937,6 +2937,13 @@ public final class BlockTypeKeys { */ public static final TypedKey GOLD_ORE = create(key("gold_ore")); + /** + * {@code minecraft:golden_dandelion} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GOLDEN_DANDELION = create(key("golden_dandelion")); + /** * {@code minecraft:granite} * @@ -5513,6 +5520,13 @@ public final class BlockTypeKeys { */ public static final TypedKey POTTED_FLOWERING_AZALEA_BUSH = create(key("potted_flowering_azalea_bush")); + /** + * {@code minecraft:potted_golden_dandelion} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey POTTED_GOLDEN_DANDELION = create(key("potted_golden_dandelion")); + /** * {@code minecraft:potted_jungle_sapling} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/CatSoundVariantKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/CatSoundVariantKeys.java new file mode 100644 index 000000000000..2fd93cf823f3 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/CatSoundVariantKeys.java @@ -0,0 +1,54 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.bukkit.entity.Cat; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#CAT_SOUND_VARIANT}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class CatSoundVariantKeys { + /** + * {@code minecraft:classic} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CLASSIC = create(key("classic")); + + /** + * {@code minecraft:royal} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ROYAL = create(key("royal")); + + private CatSoundVariantKeys() { + } + + /** + * Creates a typed key for {@link Cat.SoundVariant} in the registry {@code minecraft:cat_sound_variant}. + * + * @param key the value's key in the registry + * @return a new typed key + */ + public static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.CAT_SOUND_VARIANT, key); + } +} diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/ChickenSoundVariantKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ChickenSoundVariantKeys.java new file mode 100644 index 000000000000..a788aff2c522 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ChickenSoundVariantKeys.java @@ -0,0 +1,54 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.bukkit.entity.Chicken; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#CHICKEN_SOUND_VARIANT}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class ChickenSoundVariantKeys { + /** + * {@code minecraft:classic} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CLASSIC = create(key("classic")); + + /** + * {@code minecraft:picky} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PICKY = create(key("picky")); + + private ChickenSoundVariantKeys() { + } + + /** + * Creates a typed key for {@link Chicken.SoundVariant} in the registry {@code minecraft:chicken_sound_variant}. + * + * @param key the value's key in the registry + * @return a new typed key + */ + public static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.CHICKEN_SOUND_VARIANT, key); + } +} diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/CowSoundVariantKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/CowSoundVariantKeys.java new file mode 100644 index 000000000000..d47bf078c6f5 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/CowSoundVariantKeys.java @@ -0,0 +1,54 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.bukkit.entity.Cow; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#COW_SOUND_VARIANT}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class CowSoundVariantKeys { + /** + * {@code minecraft:classic} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CLASSIC = create(key("classic")); + + /** + * {@code minecraft:moody} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MOODY = create(key("moody")); + + private CowSoundVariantKeys() { + } + + /** + * Creates a typed key for {@link Cow.SoundVariant} in the registry {@code minecraft:cow_sound_variant}. + * + * @param key the value's key in the registry + * @return a new typed key + */ + public static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.COW_SOUND_VARIANT, key); + } +} diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/DataComponentTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/DataComponentTypeKeys.java index a3d447f8cd6d..76f44313dc63 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/DataComponentTypeKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/DataComponentTypeKeys.java @@ -25,6 +25,13 @@ @NullMarked @GeneratedClass public final class DataComponentTypeKeys { + /** + * {@code minecraft:additional_trade_cost} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ADDITIONAL_TRADE_COST = create(key("additional_trade_cost")); + /** * {@code minecraft:attack_range} * @@ -130,6 +137,13 @@ public final class DataComponentTypeKeys { */ public static final TypedKey CAT_COLLAR = create(key("cat/collar")); + /** + * {@code minecraft:cat/sound_variant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CAT_SOUND_VARIANT = create(key("cat/sound_variant")); + /** * {@code minecraft:cat/variant} * @@ -144,6 +158,13 @@ public final class DataComponentTypeKeys { */ public static final TypedKey CHARGED_PROJECTILES = create(key("charged_projectiles")); + /** + * {@code minecraft:chicken/sound_variant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CHICKEN_SOUND_VARIANT = create(key("chicken/sound_variant")); + /** * {@code minecraft:chicken/variant} * @@ -172,6 +193,13 @@ public final class DataComponentTypeKeys { */ public static final TypedKey CONTAINER_LOOT = create(key("container_loot")); + /** + * {@code minecraft:cow/sound_variant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey COW_SOUND_VARIANT = create(key("cow/sound_variant")); + /** * {@code minecraft:cow/variant} * @@ -242,6 +270,13 @@ public final class DataComponentTypeKeys { */ public static final TypedKey DEBUG_STICK_STATE = create(key("debug_stick_state")); + /** + * {@code minecraft:dye} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DYE = create(key("dye")); + /** * {@code minecraft:dyed_color} * @@ -494,6 +529,13 @@ public final class DataComponentTypeKeys { */ public static final TypedKey PIERCING_WEAPON = create(key("piercing_weapon")); + /** + * {@code minecraft:pig/sound_variant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey PIG_SOUND_VARIANT = create(key("pig/sound_variant")); + /** * {@code minecraft:pig/variant} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/ItemTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ItemTypeKeys.java index 33b92219df8b..edd4923254b8 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/ItemTypeKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/ItemTypeKeys.java @@ -3959,6 +3959,13 @@ public final class ItemTypeKeys { */ public static final TypedKey GOLDEN_CHESTPLATE = create(key("golden_chestplate")); + /** + * {@code minecraft:golden_dandelion} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey GOLDEN_DANDELION = create(key("golden_dandelion")); + /** * {@code minecraft:golden_helmet} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/PigSoundVariantKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/PigSoundVariantKeys.java new file mode 100644 index 000000000000..e1801cfd8d33 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/PigSoundVariantKeys.java @@ -0,0 +1,61 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.bukkit.entity.Pig; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#PIG_SOUND_VARIANT}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class PigSoundVariantKeys { + /** + * {@code minecraft:big} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BIG = create(key("big")); + + /** + * {@code minecraft:classic} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey CLASSIC = create(key("classic")); + + /** + * {@code minecraft:mini} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MINI = create(key("mini")); + + private PigSoundVariantKeys() { + } + + /** + * Creates a typed key for {@link Pig.SoundVariant} in the registry {@code minecraft:pig_sound_variant}. + * + * @param key the value's key in the registry + * @return a new typed key + */ + public static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.PIG_SOUND_VARIANT, key); + } +} diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/SoundEventKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/SoundEventKeys.java index f12ba25ff870..876765f6a74e 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/SoundEventKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/SoundEventKeys.java @@ -3707,6 +3707,34 @@ public final class SoundEventKeys { */ public static final TypedKey BLOCK_NOTE_BLOCK_SNARE = create(key("block.note_block.snare")); + /** + * {@code minecraft:block.note_block.trumpet} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_NOTE_BLOCK_TRUMPET = create(key("block.note_block.trumpet")); + + /** + * {@code minecraft:block.note_block.trumpet_exposed} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_NOTE_BLOCK_TRUMPET_EXPOSED = create(key("block.note_block.trumpet_exposed")); + + /** + * {@code minecraft:block.note_block.trumpet_oxidized} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_NOTE_BLOCK_TRUMPET_OXIDIZED = create(key("block.note_block.trumpet_oxidized")); + + /** + * {@code minecraft:block.note_block.trumpet_weathered} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey BLOCK_NOTE_BLOCK_TRUMPET_WEATHERED = create(key("block.note_block.trumpet_weathered")); + /** * {@code minecraft:block.note_block.xylophone} * @@ -6031,6 +6059,153 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_AXOLOTL_SWIM = create(key("entity.axolotl.swim")); + /** + * {@code minecraft:entity.baby_cat.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_AMBIENT = create(key("entity.baby_cat.ambient")); + + /** + * {@code minecraft:entity.baby_cat.beg_for_food} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_BEG_FOR_FOOD = create(key("entity.baby_cat.beg_for_food")); + + /** + * {@code minecraft:entity.baby_cat.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_DEATH = create(key("entity.baby_cat.death")); + + /** + * {@code minecraft:entity.baby_cat.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_EAT = create(key("entity.baby_cat.eat")); + + /** + * {@code minecraft:entity.baby_cat.hiss} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_HISS = create(key("entity.baby_cat.hiss")); + + /** + * {@code minecraft:entity.baby_cat.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_HURT = create(key("entity.baby_cat.hurt")); + + /** + * {@code minecraft:entity.baby_cat.purr} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_PURR = create(key("entity.baby_cat.purr")); + + /** + * {@code minecraft:entity.baby_cat.purreow} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_PURREOW = create(key("entity.baby_cat.purreow")); + + /** + * {@code minecraft:entity.baby_cat.stray_ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CAT_STRAY_AMBIENT = create(key("entity.baby_cat.stray_ambient")); + + /** + * {@code minecraft:entity.baby_chicken.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CHICKEN_AMBIENT = create(key("entity.baby_chicken.ambient")); + + /** + * {@code minecraft:entity.baby_chicken.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CHICKEN_DEATH = create(key("entity.baby_chicken.death")); + + /** + * {@code minecraft:entity.baby_chicken.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CHICKEN_HURT = create(key("entity.baby_chicken.hurt")); + + /** + * {@code minecraft:entity.baby_chicken.step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_CHICKEN_STEP = create(key("entity.baby_chicken.step")); + + /** + * {@code minecraft:entity.baby_horse.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_AMBIENT = create(key("entity.baby_horse.ambient")); + + /** + * {@code minecraft:entity.baby_horse.angry} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_ANGRY = create(key("entity.baby_horse.angry")); + + /** + * {@code minecraft:entity.baby_horse.breathe} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_BREATHE = create(key("entity.baby_horse.breathe")); + + /** + * {@code minecraft:entity.baby_horse.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_DEATH = create(key("entity.baby_horse.death")); + + /** + * {@code minecraft:entity.baby_horse.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_EAT = create(key("entity.baby_horse.eat")); + + /** + * {@code minecraft:entity.baby_horse.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_HURT = create(key("entity.baby_horse.hurt")); + + /** + * {@code minecraft:entity.baby_horse.land} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_LAND = create(key("entity.baby_horse.land")); + + /** + * {@code minecraft:entity.baby_horse.step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_HORSE_STEP = create(key("entity.baby_horse.step")); + /** * {@code minecraft:entity.baby_nautilus.ambient} * @@ -6087,6 +6262,90 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_BABY_NAUTILUS_SWIM = create(key("entity.baby_nautilus.swim")); + /** + * {@code minecraft:entity.baby_pig.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_PIG_AMBIENT = create(key("entity.baby_pig.ambient")); + + /** + * {@code minecraft:entity.baby_pig.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_PIG_DEATH = create(key("entity.baby_pig.death")); + + /** + * {@code minecraft:entity.baby_pig.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_PIG_EAT = create(key("entity.baby_pig.eat")); + + /** + * {@code minecraft:entity.baby_pig.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_PIG_HURT = create(key("entity.baby_pig.hurt")); + + /** + * {@code minecraft:entity.baby_pig.step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_PIG_STEP = create(key("entity.baby_pig.step")); + + /** + * {@code minecraft:entity.baby_wolf.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_AMBIENT = create(key("entity.baby_wolf.ambient")); + + /** + * {@code minecraft:entity.baby_wolf.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_DEATH = create(key("entity.baby_wolf.death")); + + /** + * {@code minecraft:entity.baby_wolf.growl} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_GROWL = create(key("entity.baby_wolf.growl")); + + /** + * {@code minecraft:entity.baby_wolf.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_HURT = create(key("entity.baby_wolf.hurt")); + + /** + * {@code minecraft:entity.baby_wolf.pant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_PANT = create(key("entity.baby_wolf.pant")); + + /** + * {@code minecraft:entity.baby_wolf.step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_STEP = create(key("entity.baby_wolf.step")); + + /** + * {@code minecraft:entity.baby_wolf.whine} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_BABY_WOLF_WHINE = create(key("entity.baby_wolf.whine")); + /** * {@code minecraft:entity.bat.ambient} * @@ -6556,6 +6815,69 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_CAT_STRAY_AMBIENT = create(key("entity.cat.stray_ambient")); + /** + * {@code minecraft:entity.cat_royal.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_AMBIENT = create(key("entity.cat_royal.ambient")); + + /** + * {@code minecraft:entity.cat_royal.beg_for_food} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_BEG_FOR_FOOD = create(key("entity.cat_royal.beg_for_food")); + + /** + * {@code minecraft:entity.cat_royal.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_DEATH = create(key("entity.cat_royal.death")); + + /** + * {@code minecraft:entity.cat_royal.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_EAT = create(key("entity.cat_royal.eat")); + + /** + * {@code minecraft:entity.cat_royal.hiss} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_HISS = create(key("entity.cat_royal.hiss")); + + /** + * {@code minecraft:entity.cat_royal.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_HURT = create(key("entity.cat_royal.hurt")); + + /** + * {@code minecraft:entity.cat_royal.purr} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_PURR = create(key("entity.cat_royal.purr")); + + /** + * {@code minecraft:entity.cat_royal.purreow} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_PURREOW = create(key("entity.cat_royal.purreow")); + + /** + * {@code minecraft:entity.cat_royal.stray_ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CAT_ROYAL_STRAY_AMBIENT = create(key("entity.cat_royal.stray_ambient")); + /** * {@code minecraft:entity.chicken.ambient} * @@ -6591,6 +6913,27 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_CHICKEN_STEP = create(key("entity.chicken.step")); + /** + * {@code minecraft:entity.chicken_picky.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CHICKEN_PICKY_AMBIENT = create(key("entity.chicken_picky.ambient")); + + /** + * {@code minecraft:entity.chicken_picky.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CHICKEN_PICKY_DEATH = create(key("entity.chicken_picky.death")); + + /** + * {@code minecraft:entity.chicken_picky.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_CHICKEN_PICKY_HURT = create(key("entity.chicken_picky.hurt")); + /** * {@code minecraft:entity.cod.ambient} * @@ -6787,6 +7130,34 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_COW_STEP = create(key("entity.cow.step")); + /** + * {@code minecraft:entity.cow_moody.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_COW_MOODY_AMBIENT = create(key("entity.cow_moody.ambient")); + + /** + * {@code minecraft:entity.cow_moody.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_COW_MOODY_DEATH = create(key("entity.cow_moody.death")); + + /** + * {@code minecraft:entity.cow_moody.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_COW_MOODY_HURT = create(key("entity.cow_moody.hurt")); + + /** + * {@code minecraft:entity.cow_moody.step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_COW_MOODY_STEP = create(key("entity.cow_moody.step")); + /** * {@code minecraft:entity.creaking.activate} * @@ -9223,6 +9594,13 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_PIG_DEATH = create(key("entity.pig.death")); + /** + * {@code minecraft:entity.pig.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_EAT = create(key("entity.pig.eat")); + /** * {@code minecraft:entity.pig.hurt} * @@ -9244,6 +9622,62 @@ public final class SoundEventKeys { */ public static final TypedKey ENTITY_PIG_STEP = create(key("entity.pig.step")); + /** + * {@code minecraft:entity.pig_big.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_BIG_AMBIENT = create(key("entity.pig_big.ambient")); + + /** + * {@code minecraft:entity.pig_big.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_BIG_DEATH = create(key("entity.pig_big.death")); + + /** + * {@code minecraft:entity.pig_big.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_BIG_EAT = create(key("entity.pig_big.eat")); + + /** + * {@code minecraft:entity.pig_big.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_BIG_HURT = create(key("entity.pig_big.hurt")); + + /** + * {@code minecraft:entity.pig_mini.ambient} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_MINI_AMBIENT = create(key("entity.pig_mini.ambient")); + + /** + * {@code minecraft:entity.pig_mini.death} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_MINI_DEATH = create(key("entity.pig_mini.death")); + + /** + * {@code minecraft:entity.pig_mini.eat} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_MINI_EAT = create(key("entity.pig_mini.eat")); + + /** + * {@code minecraft:entity.pig_mini.hurt} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_PIG_MINI_HURT = create(key("entity.pig_mini.hurt")); + /** * {@code minecraft:entity.piglin.admiring_item} * @@ -12107,6 +12541,20 @@ public final class SoundEventKeys { */ public static final TypedKey ITEM_GOAT_HORN_SOUND_7 = create(key("item.goat_horn.sound.7")); + /** + * {@code minecraft:item.golden_dandelion.unuse} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_GOLDEN_DANDELION_UNUSE = create(key("item.golden_dandelion.unuse")); + + /** + * {@code minecraft:item.golden_dandelion.use} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ITEM_GOLDEN_DANDELION_USE = create(key("item.golden_dandelion.use")); + /** * {@code minecraft:item.hoe.till} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/BlockTypeTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/BlockTypeTagKeys.java index 4f1e44542145..fba1331fc5bd 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/BlockTypeTagKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/BlockTypeTagKeys.java @@ -116,13 +116,6 @@ public final class BlockTypeTagKeys { */ public static final TagKey BAMBOO_BLOCKS = create(key("bamboo_blocks")); - /** - * {@code #minecraft:bamboo_plantable_on} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TagKey BAMBOO_PLANTABLE_ON = create(key("bamboo_plantable_on")); - /** * {@code #minecraft:banners} * @@ -194,11 +187,18 @@ public final class BlockTypeTagKeys { public static final TagKey BEEHIVES = create(key("beehives")); /** - * {@code #minecraft:big_dripleaf_placeable} + * {@code #minecraft:beneath_bamboo_podzol_replaceable} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey BIG_DRIPLEAF_PLACEABLE = create(key("big_dripleaf_placeable")); + public static final TagKey BENEATH_BAMBOO_PODZOL_REPLACEABLE = create(key("beneath_bamboo_podzol_replaceable")); + + /** + * {@code #minecraft:beneath_tree_podzol_replaceable} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey BENEATH_TREE_PODZOL_REPLACEABLE = create(key("beneath_tree_podzol_replaceable")); /** * {@code #minecraft:birch_logs} @@ -263,6 +263,34 @@ public final class BlockTypeTagKeys { */ public static final TagKey CANDLES = create(key("candles")); + /** + * {@code #minecraft:cannot_replace_below_tree_trunk} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CANNOT_REPLACE_BELOW_TREE_TRUNK = create(key("cannot_replace_below_tree_trunk")); + + /** + * {@code #minecraft:cannot_support_kelp} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CANNOT_SUPPORT_KELP = create(key("cannot_support_kelp")); + + /** + * {@code #minecraft:cannot_support_seagrass} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CANNOT_SUPPORT_SEAGRASS = create(key("cannot_support_seagrass")); + + /** + * {@code #minecraft:cannot_support_snow_layer} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CANNOT_SUPPORT_SNOW_LAYER = create(key("cannot_support_snow_layer")); + /** * {@code #minecraft:cauldrons} * @@ -481,25 +509,32 @@ public final class BlockTypeTagKeys { public static final TagKey DRIPSTONE_REPLACEABLE_BLOCKS = create(key("dripstone_replaceable_blocks")); /** - * {@code #minecraft:dry_vegetation_may_place_on} + * {@code #minecraft:edible_for_sheep} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey DRY_VEGETATION_MAY_PLACE_ON = create(key("dry_vegetation_may_place_on")); + public static final TagKey EDIBLE_FOR_SHEEP = create(key("edible_for_sheep")); /** - * {@code #minecraft:edible_for_sheep} + * {@code #minecraft:emerald_ores} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey EDIBLE_FOR_SHEEP = create(key("edible_for_sheep")); + public static final TagKey EMERALD_ORES = create(key("emerald_ores")); /** - * {@code #minecraft:emerald_ores} + * {@code #minecraft:enables_bubble_column_drag_down} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey EMERALD_ORES = create(key("emerald_ores")); + public static final TagKey ENABLES_BUBBLE_COLUMN_DRAG_DOWN = create(key("enables_bubble_column_drag_down")); + + /** + * {@code #minecraft:enables_bubble_column_push_up} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey ENABLES_BUBBLE_COLUMN_PUSH_UP = create(key("enables_bubble_column_push_up")); /** * {@code #minecraft:enchantment_power_provider} @@ -571,6 +606,13 @@ public final class BlockTypeTagKeys { */ public static final TagKey FLOWERS = create(key("flowers")); + /** + * {@code #minecraft:forest_rock_can_place_on} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey FOREST_ROCK_CAN_PLACE_ON = create(key("forest_rock_can_place_on")); + /** * {@code #minecraft:foxes_spawnable_on} * @@ -613,6 +655,20 @@ public final class BlockTypeTagKeys { */ public static final TagKey GOLD_ORES = create(key("gold_ores")); + /** + * {@code #minecraft:grass_blocks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey GRASS_BLOCKS = create(key("grass_blocks")); + + /** + * {@code #minecraft:grows_crops} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey GROWS_CROPS = create(key("grows_crops")); + /** * {@code #minecraft:guarded_by_piglins} * @@ -634,6 +690,20 @@ public final class BlockTypeTagKeys { */ public static final TagKey HOGLIN_REPELLENTS = create(key("hoglin_repellents")); + /** + * {@code #minecraft:huge_brown_mushroom_can_place_on} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey HUGE_BROWN_MUSHROOM_CAN_PLACE_ON = create(key("huge_brown_mushroom_can_place_on")); + + /** + * {@code #minecraft:huge_red_mushroom_can_place_on} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey HUGE_RED_MUSHROOM_CAN_PLACE_ON = create(key("huge_red_mushroom_can_place_on")); + /** * {@code #minecraft:ice} * @@ -641,6 +711,13 @@ public final class BlockTypeTagKeys { */ public static final TagKey ICE = create(key("ice")); + /** + * {@code #minecraft:ice_spike_replaceable} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey ICE_SPIKE_REPLACEABLE = create(key("ice_spike_replaceable")); + /** * {@code #minecraft:impermeable} * @@ -872,6 +949,13 @@ public final class BlockTypeTagKeys { */ public static final TagKey MOOSHROOMS_SPAWNABLE_ON = create(key("mooshrooms_spawnable_on")); + /** + * {@code #minecraft:moss_blocks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey MOSS_BLOCKS = create(key("moss_blocks")); + /** * {@code #minecraft:moss_replaceable} * @@ -880,11 +964,11 @@ public final class BlockTypeTagKeys { public static final TagKey MOSS_REPLACEABLE = create(key("moss_replaceable")); /** - * {@code #minecraft:mushroom_grow_block} + * {@code #minecraft:mud} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey MUSHROOM_GROW_BLOCK = create(key("mushroom_grow_block")); + public static final TagKey MUD = create(key("mud")); /** * {@code #minecraft:needs_diamond_tool} @@ -935,6 +1019,13 @@ public final class BlockTypeTagKeys { */ public static final TagKey OCCLUDES_VIBRATION_SIGNALS = create(key("occludes_vibration_signals")); + /** + * {@code #minecraft:overrides_mushroom_light_requirement} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT = create(key("overrides_mushroom_light_requirement")); + /** * {@code #minecraft:overworld_carver_replaceables} * @@ -1005,6 +1096,13 @@ public final class BlockTypeTagKeys { */ public static final TagKey PREVENT_MOB_SPAWNING_INSIDE = create(key("prevent_mob_spawning_inside")); + /** + * {@code #minecraft:prevents_nearby_leaf_decay} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey PREVENTS_NEARBY_LEAF_DECAY = create(key("prevents_nearby_leaf_decay")); + /** * {@code #minecraft:rabbits_spawnable_on} * @@ -1096,13 +1194,6 @@ public final class BlockTypeTagKeys { */ public static final TagKey SLABS = create(key("slabs")); - /** - * {@code #minecraft:small_dripleaf_placeable} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TagKey SMALL_DRIPLEAF_PLACEABLE = create(key("small_dripleaf_placeable")); - /** * {@code #minecraft:small_flowers} * @@ -1145,20 +1236,6 @@ public final class BlockTypeTagKeys { */ public static final TagKey SNOW = create(key("snow")); - /** - * {@code #minecraft:snow_layer_can_survive_on} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TagKey SNOW_LAYER_CAN_SURVIVE_ON = create(key("snow_layer_can_survive_on")); - - /** - * {@code #minecraft:snow_layer_cannot_survive_on} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TagKey SNOW_LAYER_CANNOT_SURVIVE_ON = create(key("snow_layer_cannot_survive_on")); - /** * {@code #minecraft:soul_fire_base_blocks} * @@ -1229,6 +1306,237 @@ public final class BlockTypeTagKeys { */ public static final TagKey STRIDER_WARM_BLOCKS = create(key("strider_warm_blocks")); + /** + * {@code #minecraft:substrate_overworld} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUBSTRATE_OVERWORLD = create(key("substrate_overworld")); + + /** + * {@code #minecraft:support_override_cactus_flower} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORT_OVERRIDE_CACTUS_FLOWER = create(key("support_override_cactus_flower")); + + /** + * {@code #minecraft:support_override_snow_layer} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORT_OVERRIDE_SNOW_LAYER = create(key("support_override_snow_layer")); + + /** + * {@code #minecraft:supports_azalea} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_AZALEA = create(key("supports_azalea")); + + /** + * {@code #minecraft:supports_bamboo} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_BAMBOO = create(key("supports_bamboo")); + + /** + * {@code #minecraft:supports_big_dripleaf} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_BIG_DRIPLEAF = create(key("supports_big_dripleaf")); + + /** + * {@code #minecraft:supports_cactus} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CACTUS = create(key("supports_cactus")); + + /** + * {@code #minecraft:supports_chorus_flower} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CHORUS_FLOWER = create(key("supports_chorus_flower")); + + /** + * {@code #minecraft:supports_chorus_plant} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CHORUS_PLANT = create(key("supports_chorus_plant")); + + /** + * {@code #minecraft:supports_cocoa} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_COCOA = create(key("supports_cocoa")); + + /** + * {@code #minecraft:supports_crimson_fungus} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CRIMSON_FUNGUS = create(key("supports_crimson_fungus")); + + /** + * {@code #minecraft:supports_crimson_roots} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CRIMSON_ROOTS = create(key("supports_crimson_roots")); + + /** + * {@code #minecraft:supports_crops} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_CROPS = create(key("supports_crops")); + + /** + * {@code #minecraft:supports_dry_vegetation} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_DRY_VEGETATION = create(key("supports_dry_vegetation")); + + /** + * {@code #minecraft:supports_frogspawn} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_FROGSPAWN = create(key("supports_frogspawn")); + + /** + * {@code #minecraft:supports_hanging_mangrove_propagule} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_HANGING_MANGROVE_PROPAGULE = create(key("supports_hanging_mangrove_propagule")); + + /** + * {@code #minecraft:supports_lily_pad} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_LILY_PAD = create(key("supports_lily_pad")); + + /** + * {@code #minecraft:supports_mangrove_propagule} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_MANGROVE_PROPAGULE = create(key("supports_mangrove_propagule")); + + /** + * {@code #minecraft:supports_melon_stem} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_MELON_STEM = create(key("supports_melon_stem")); + + /** + * {@code #minecraft:supports_melon_stem_fruit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_MELON_STEM_FRUIT = create(key("supports_melon_stem_fruit")); + + /** + * {@code #minecraft:supports_nether_sprouts} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_NETHER_SPROUTS = create(key("supports_nether_sprouts")); + + /** + * {@code #minecraft:supports_nether_wart} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_NETHER_WART = create(key("supports_nether_wart")); + + /** + * {@code #minecraft:supports_pumpkin_stem} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_PUMPKIN_STEM = create(key("supports_pumpkin_stem")); + + /** + * {@code #minecraft:supports_pumpkin_stem_fruit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_PUMPKIN_STEM_FRUIT = create(key("supports_pumpkin_stem_fruit")); + + /** + * {@code #minecraft:supports_small_dripleaf} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_SMALL_DRIPLEAF = create(key("supports_small_dripleaf")); + + /** + * {@code #minecraft:supports_stem_crops} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_STEM_CROPS = create(key("supports_stem_crops")); + + /** + * {@code #minecraft:supports_stem_fruit} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_STEM_FRUIT = create(key("supports_stem_fruit")); + + /** + * {@code #minecraft:supports_sugar_cane} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_SUGAR_CANE = create(key("supports_sugar_cane")); + + /** + * {@code #minecraft:supports_sugar_cane_adjacently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_SUGAR_CANE_ADJACENTLY = create(key("supports_sugar_cane_adjacently")); + + /** + * {@code #minecraft:supports_vegetation} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_VEGETATION = create(key("supports_vegetation")); + + /** + * {@code #minecraft:supports_warped_fungus} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_WARPED_FUNGUS = create(key("supports_warped_fungus")); + + /** + * {@code #minecraft:supports_warped_roots} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_WARPED_ROOTS = create(key("supports_warped_roots")); + + /** + * {@code #minecraft:supports_wither_rose} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_WITHER_ROSE = create(key("supports_wither_rose")); + /** * {@code #minecraft:sword_efficient} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EnchantmentTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EnchantmentTagKeys.java index ecd7ef06057f..b15d2c420c76 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EnchantmentTagKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EnchantmentTagKeys.java @@ -183,15 +183,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_DESERT_COMMON = create(key("trades/desert_common")); - /** - * {@code #minecraft:trades/desert_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_DESERT_SPECIAL = create(key("trades/desert_special")); - /** * {@code #minecraft:trades/jungle_common} * @@ -201,15 +192,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_JUNGLE_COMMON = create(key("trades/jungle_common")); - /** - * {@code #minecraft:trades/jungle_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_JUNGLE_SPECIAL = create(key("trades/jungle_special")); - /** * {@code #minecraft:trades/plains_common} * @@ -219,15 +201,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_PLAINS_COMMON = create(key("trades/plains_common")); - /** - * {@code #minecraft:trades/plains_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_PLAINS_SPECIAL = create(key("trades/plains_special")); - /** * {@code #minecraft:trades/savanna_common} * @@ -237,15 +210,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_SAVANNA_COMMON = create(key("trades/savanna_common")); - /** - * {@code #minecraft:trades/savanna_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_SAVANNA_SPECIAL = create(key("trades/savanna_special")); - /** * {@code #minecraft:trades/snow_common} * @@ -255,15 +219,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_SNOW_COMMON = create(key("trades/snow_common")); - /** - * {@code #minecraft:trades/snow_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_SNOW_SPECIAL = create(key("trades/snow_special")); - /** * {@code #minecraft:trades/swamp_common} * @@ -273,15 +228,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_SWAMP_COMMON = create(key("trades/swamp_common")); - /** - * {@code #minecraft:trades/swamp_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_SWAMP_SPECIAL = create(key("trades/swamp_special")); - /** * {@code #minecraft:trades/taiga_common} * @@ -291,15 +237,6 @@ public final class EnchantmentTagKeys { @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) public static final TagKey TRADES_TAIGA_COMMON = create(key("trades/taiga_common")); - /** - * {@code #minecraft:trades/taiga_special} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - @ApiStatus.Experimental - @MinecraftExperimental(MinecraftExperimental.Requires.TRADE_REBALANCE) - public static final TagKey TRADES_TAIGA_SPECIAL = create(key("trades/taiga_special")); - /** * {@code #minecraft:treasure} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EntityTypeTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EntityTypeTagKeys.java index f24cd0efc90f..e1cd2c06e838 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EntityTypeTagKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/EntityTypeTagKeys.java @@ -144,6 +144,13 @@ public final class EntityTypeTagKeys { */ public static final TagKey CANDIDATE_FOR_IRON_GOLEM_GIFT = create(key("candidate_for_iron_golem_gift")); + /** + * {@code #minecraft:cannot_be_age_locked} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CANNOT_BE_AGE_LOCKED = create(key("cannot_be_age_locked")); + /** * {@code #minecraft:cannot_be_pushed_onto_boats} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/FluidTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/FluidTagKeys.java index 5b38f4d91c57..a9fc24a6eb7c 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/FluidTagKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/FluidTagKeys.java @@ -25,6 +25,13 @@ @NullMarked @GeneratedClass public final class FluidTagKeys { + /** + * {@code #minecraft:bubble_column_can_occupy} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey BUBBLE_COLUMN_CAN_OCCUPY = create(key("bubble_column_can_occupy")); + /** * {@code #minecraft:lava} * @@ -32,6 +39,27 @@ public final class FluidTagKeys { */ public static final TagKey LAVA = create(key("lava")); + /** + * {@code #minecraft:supports_frogspawn} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_FROGSPAWN = create(key("supports_frogspawn")); + + /** + * {@code #minecraft:supports_lily_pad} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_LILY_PAD = create(key("supports_lily_pad")); + + /** + * {@code #minecraft:supports_sugar_cane_adjacently} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey SUPPORTS_SUGAR_CANE_ADJACENTLY = create(key("supports_sugar_cane_adjacently")); + /** * {@code #minecraft:water} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/ItemTypeTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/ItemTypeTagKeys.java index 40202e9e23ad..1a73196592a0 100644 --- a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/ItemTypeTagKeys.java +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/ItemTypeTagKeys.java @@ -186,6 +186,13 @@ public final class ItemTypeTagKeys { */ public static final TagKey CANDLES = create(key("candles")); + /** + * {@code #minecraft:cat_collar_dyes} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CAT_COLLAR_DYES = create(key("cat_collar_dyes")); + /** * {@code #minecraft:cat_food} * @@ -193,6 +200,13 @@ public final class ItemTypeTagKeys { */ public static final TagKey CAT_FOOD = create(key("cat_food")); + /** + * {@code #minecraft:cauldron_can_remove_dye} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey CAULDRON_CAN_REMOVE_DYE = create(key("cauldron_can_remove_dye")); + /** * {@code #minecraft:chains} * @@ -397,11 +411,11 @@ public final class ItemTypeTagKeys { public static final TagKey DUPLICATES_ALLAYS = create(key("duplicates_allays")); /** - * {@code #minecraft:dyeable} + * {@code #minecraft:dyes} * * @apiNote This field is version-dependant and may be removed in future Minecraft versions */ - public static final TagKey DYEABLE = create(key("dyeable")); + public static final TagKey DYES = create(key("dyes")); /** * {@code #minecraft:eggs} @@ -655,6 +669,13 @@ public final class ItemTypeTagKeys { */ public static final TagKey GOLD_TOOL_MATERIALS = create(key("gold_tool_materials")); + /** + * {@code #minecraft:grass_blocks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey GRASS_BLOCKS = create(key("grass_blocks")); + /** * {@code #minecraft:hanging_signs} * @@ -816,6 +837,20 @@ public final class ItemTypeTagKeys { */ public static final TagKey LOGS_THAT_BURN = create(key("logs_that_burn")); + /** + * {@code #minecraft:loom_dyes} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey LOOM_DYES = create(key("loom_dyes")); + + /** + * {@code #minecraft:loom_patterns} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey LOOM_PATTERNS = create(key("loom_patterns")); + /** * {@code #minecraft:mangrove_logs} * @@ -837,6 +872,27 @@ public final class ItemTypeTagKeys { */ public static final TagKey MEAT = create(key("meat")); + /** + * {@code #minecraft:metal_nuggets} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey METAL_NUGGETS = create(key("metal_nuggets")); + + /** + * {@code #minecraft:moss_blocks} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey MOSS_BLOCKS = create(key("moss_blocks")); + + /** + * {@code #minecraft:mud} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey MUD = create(key("mud")); + /** * {@code #minecraft:nautilus_bucket_food} * @@ -1320,6 +1376,13 @@ public final class ItemTypeTagKeys { */ public static final TagKey WITHER_SKELETON_DISLIKED_WEAPONS = create(key("wither_skeleton_disliked_weapons")); + /** + * {@code #minecraft:wolf_collar_dyes} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey WOLF_COLLAR_DYES = create(key("wolf_collar_dyes")); + /** * {@code #minecraft:wolf_food} * diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/PotionTypeTagKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/PotionTypeTagKeys.java new file mode 100644 index 000000000000..fd20b7a6e394 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/PotionTypeTagKeys.java @@ -0,0 +1,47 @@ +package io.papermc.paper.registry.keys.tags; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.tag.TagKey; +import net.kyori.adventure.key.Key; +import org.bukkit.potion.PotionType; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla tag keys for {@link RegistryKey#POTION}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class PotionTypeTagKeys { + /** + * {@code #minecraft:tradeable} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TagKey TRADEABLE = create(key("tradeable")); + + private PotionTypeTagKeys() { + } + + /** + * Creates a tag key for {@link PotionType} in the registry {@code minecraft:potion}. + * + * @param key the tag key's key + * @return a new tag key + */ + public static TagKey create(final Key key) { + return TagKey.create(RegistryKey.POTION, key); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java index 1fcdc62cff07..de9f62cd3eae 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java @@ -45,7 +45,7 @@ import io.papermc.paper.datacomponent.item.WritableBookContent; import io.papermc.paper.datacomponent.item.WrittenBookContent; import io.papermc.paper.item.MapPostProcessing; -import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.set.RegistryKeySet; import java.util.List; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; @@ -239,8 +239,9 @@ public final class DataComponentTypes { * @see #ENCHANTMENTS */ public static final DataComponentType.Valued STORED_ENCHANTMENTS = valued("stored_enchantments"); + public static final DataComponentType.Valued DYE = valued("dye"); /** - * Represents a color applied to a dyeable item (in the {@link io.papermc.paper.registry.keys.tags.ItemTypeTagKeys#DYEABLE} item tag). + * Represents a color applied to a dyeable item. */ public static final DataComponentType.Valued DYED_COLOR = valued("dyed_color"); /** @@ -306,7 +307,7 @@ public final class DataComponentTypes { */ public static final DataComponentType.Valued OMINOUS_BOTTLE_AMPLIFIER = valued("ominous_bottle_amplifier"); public static final DataComponentType.Valued JUKEBOX_PLAYABLE = valued("jukebox_playable"); - public static final DataComponentType.Valued> PROVIDES_BANNER_PATTERNS = valued("provides_banner_patterns"); + public static final DataComponentType.Valued> PROVIDES_BANNER_PATTERNS = valued("provides_banner_patterns"); /** * List of recipes that should be unlocked when using the Knowledge Book item. */ @@ -378,9 +379,11 @@ public final class DataComponentTypes { public static final DataComponentType.Valued MOOSHROOM_VARIANT = valued("mooshroom/variant"); public static final DataComponentType.Valued RABBIT_VARIANT = valued("rabbit/variant"); public static final DataComponentType.Valued PIG_VARIANT = valued("pig/variant"); + public static final DataComponentType.Valued PIG_SOUND_VARIANT = valued("pig/sound_variant"); public static final DataComponentType.Valued COW_VARIANT = valued("cow/variant"); + public static final DataComponentType.Valued COW_SOUND_VARIANT = valued("cow/sound_variant"); public static final DataComponentType.Valued CHICKEN_VARIANT = valued("chicken/variant"); - // This is a eitherholder? Why specifically the chicken?? Oh wait this is prolly for chicken egg cause legacy item loading + public static final DataComponentType.Valued CHICKEN_SOUND_VARIANT = valued("chicken/sound_variant"); public static final DataComponentType.Valued FROG_VARIANT = valued("frog/variant"); public static final DataComponentType.Valued HORSE_VARIANT = valued("horse/variant"); public static final DataComponentType.Valued PAINTING_VARIANT = valued("painting/variant"); @@ -388,6 +391,7 @@ public final class DataComponentTypes { public static final DataComponentType.Valued AXOLOTL_VARIANT = valued("axolotl/variant"); public static final DataComponentType.Valued ZOMBIE_NAUTILUS_VARIANT = valued("zombie_nautilus/variant"); public static final DataComponentType.Valued CAT_VARIANT = valued("cat/variant"); + public static final DataComponentType.Valued CAT_SOUND_VARIANT = valued("cat/sound_variant"); public static final DataComponentType.Valued CAT_COLLAR = valued("cat/collar"); public static final DataComponentType.Valued SHEEP_COLOR = valued("sheep/color"); public static final DataComponentType.Valued SHULKER_COLOR = valued("shulker/color"); diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/BlocksAttacks.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/BlocksAttacks.java index e36616f7ab30..6d94fed93ede 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/BlocksAttacks.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/BlocksAttacks.java @@ -3,7 +3,7 @@ import io.papermc.paper.datacomponent.DataComponentBuilder; import io.papermc.paper.datacomponent.item.blocksattacks.DamageReduction; import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction; -import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.set.RegistryKeySet; import java.util.List; import net.kyori.adventure.key.Key; import org.bukkit.damage.DamageType; @@ -68,7 +68,7 @@ static Builder blocksAttacks() { * @return a damage type tag key, or null if there is no such tag key */ @Contract(pure = true) - @Nullable TagKey bypassedBy(); + @Nullable RegistryKeySet bypassedBy(); /** * Gets the key sound to play when an attack is successfully blocked. @@ -109,7 +109,7 @@ interface Builder extends DataComponentBuilder { Builder itemDamage(ItemDamageFunction function); @Contract(value = "_ -> this", mutates = "this") - Builder bypassedBy(@Nullable TagKey bypassedBy); + Builder bypassedBy(@Nullable RegistryKeySet bypassedBy); @Contract(value = "_ -> this", mutates = "this") Builder blockSound(@Nullable Key sound); diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java index 384098ea55d7..79e03746c5c3 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java @@ -1,6 +1,6 @@ package io.papermc.paper.datacomponent.item; -import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.set.RegistryKeySet; import org.bukkit.damage.DamageType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; @@ -16,15 +16,15 @@ public interface DamageResistant { @Contract(value = "_ -> new", pure = true) - static DamageResistant damageResistant(final TagKey types) { + static DamageResistant damageResistant(final RegistryKeySet types) { return ItemComponentTypesBridge.bridge().damageResistant(types); } /** * The types that this damage type is invincible to. * - * @return the key of the tag holding the respective damage types. + * @return the registry key set holding the respective damage types. */ @Contract(value = "-> new", pure = true) - TagKey types(); + RegistryKeySet types(); } diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java index 9a35d98bc101..c74366daa72f 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java @@ -100,7 +100,7 @@ static ItemComponentTypesBridge bridge() { UseCooldown.Builder useCooldown(final float seconds); - DamageResistant damageResistant(TagKey types); + DamageResistant damageResistant(RegistryKeySet types); Enchantable enchantable(int level); diff --git a/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java b/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java index c44006faf327..73569979b732 100644 --- a/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java +++ b/paper-api/src/main/java/io/papermc/paper/event/world/WorldGameRuleChangeEvent.java @@ -11,7 +11,8 @@ import org.jspecify.annotations.Nullable; /** - * Called when a world's gamerule is changed, either by command or by api. + * Called when a world's gamerule is changed, either by command, world options menu, or by api. + * @see Modifying game rules - Minecraft wiki */ @NullMarked public class WorldGameRuleChangeEvent extends WorldEvent implements Cancellable { diff --git a/paper-api/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java b/paper-api/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java index 906f3912f9ba..25c663b6852f 100644 --- a/paper-api/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java +++ b/paper-api/src/main/java/io/papermc/paper/event/world/border/WorldBorderBoundsChangeEvent.java @@ -68,7 +68,7 @@ public double getNewSize() { * @param newSize the new size */ public void setNewSize(final double newSize) { - this.newSize = Math.clamp(newSize, 1.0D, this.worldBorder.getMaxSize()); + this.newSize = Math.clamp(newSize, 1.0, this.worldBorder.getMaxSize()); } /** diff --git a/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java b/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java index 5843768d0be2..7071cacd66ef 100644 --- a/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java +++ b/paper-api/src/main/java/io/papermc/paper/item/MapPostProcessing.java @@ -1,6 +1,8 @@ package io.papermc.paper.item; public enum MapPostProcessing { + // Start generate - MapPostProcessing LOCK, - SCALE + SCALE; + // End generate - MapPostProcessing } diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index dcee3d88f5b7..de4ff2303c5a 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -201,6 +201,11 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.CatVariantKeys */ RegistryKey CAT_VARIANT = create("cat_variant"); + /** + * Data-driven registry for cat sound variants. + * @see io.papermc.paper.registry.keys.CatSoundVariantKeys + */ + RegistryKey CAT_SOUND_VARIANT = create("cat_sound_variant"); /** * Data-driven registry for frog variants. * @see io.papermc.paper.registry.keys.FrogVariantKeys @@ -211,16 +216,31 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.ChickenVariantKeys */ RegistryKey CHICKEN_VARIANT = create("chicken_variant"); + /** + * Data-driven registry for chicken sound variants. + * @see io.papermc.paper.registry.keys.ChickenSoundVariantKeys + */ + RegistryKey CHICKEN_SOUND_VARIANT = create("chicken_sound_variant"); /** * Data-driven registry for cow variants. * @see io.papermc.paper.registry.keys.CowVariantKeys */ RegistryKey COW_VARIANT = create("cow_variant"); + /** + * Data-driven registry for cow sound variants. + * @see io.papermc.paper.registry.keys.CowSoundVariantKeys + */ + RegistryKey COW_SOUND_VARIANT = create("cow_sound_variant"); /** * Data-driven registry for pig variants. * @see io.papermc.paper.registry.keys.PigVariantKeys */ RegistryKey PIG_VARIANT = create("pig_variant"); + /** + * Data-driven registry for pig sound variants. + * @see io.papermc.paper.registry.keys.PigSoundVariantKeys + */ + RegistryKey PIG_SOUND_VARIANT = create("pig_sound_variant"); /** * Data-driven registry for zombie nautilus variants. * @see io.papermc.paper.registry.keys.ZombieNautilusVariantKeys diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/CatTypeRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/CatTypeRegistryEntry.java index b818d61cd66d..c6b1c4a9066d 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/data/CatTypeRegistryEntry.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/CatTypeRegistryEntry.java @@ -20,12 +20,20 @@ public interface CatTypeRegistryEntry { */ ClientTextureAsset clientTextureAsset(); + /** + * Provides the client texture asset of the cat type for baby cats. + * + * @return the baby client texture asset. + */ + ClientTextureAsset babyClientTextureAsset(); + /** * A mutable builder for the {@link CatTypeRegistryEntry} plugins may change in applicable registry events. *

* The following values are required for each builder: *

    *
  • {@link #clientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyClientTextureAsset(ClientTextureAsset)}
  • *
*/ @ApiStatus.Experimental @@ -41,5 +49,15 @@ interface Builder extends CatTypeRegistryEntry, RegistryBuilder { */ @Contract(value = "_ -> this", mutates = "this") Builder clientTextureAsset(ClientTextureAsset clientTextureAsset); + + /** + * Sets the client texture asset of the cat type for baby cats. + * + * @param babyClientTextureAsset the baby client texture asset. + * @return this builder instance. + * @see CatTypeRegistryEntry#babyClientTextureAsset() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder babyClientTextureAsset(ClientTextureAsset babyClientTextureAsset); } } diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/ChickenVariantRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/ChickenVariantRegistryEntry.java index 104c01ddc353..f70d189203d5 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/data/ChickenVariantRegistryEntry.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/ChickenVariantRegistryEntry.java @@ -35,6 +35,13 @@ enum Model { */ ClientTextureAsset clientTextureAsset(); + /** + * Provides the client texture asset of the baby chicken variant, which represents the texture to use. + * + * @return the baby client texture asset. + */ + ClientTextureAsset babyClientTextureAsset(); + /** * Provides the model of the chicken variant. * @@ -48,6 +55,7 @@ enum Model { * The following values are required for each builder: *
    *
  • {@link #clientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyClientTextureAsset(ClientTextureAsset)}
  • *
  • {@link #model(Model)}
  • *
*/ @@ -65,6 +73,16 @@ interface Builder extends ChickenVariantRegistryEntry, RegistryBuilder *
  • {@link #clientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyClientTextureAsset(ClientTextureAsset)}
  • *
  • {@link #model(Model)}
  • * */ @@ -70,6 +78,16 @@ interface Builder extends CowVariantRegistryEntry, RegistryBuilder @Contract(value = "_ -> this", mutates = "this") Builder clientTextureAsset(ClientTextureAsset clientTextureAsset); + /** + * Sets the client texture asset of the baby cow variant, which is the location of the texture to use. + * + * @param babyClientTextureAsset the baby client texture asset. + * @return this builder instance. + * @see CowVariantRegistryEntry#babyClientTextureAsset() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder babyClientTextureAsset(ClientTextureAsset babyClientTextureAsset); + /** * Sets the model to use for this cow variant. * diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/PigVariantRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/PigVariantRegistryEntry.java index 02c043e835d7..0b482be5990f 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/data/PigVariantRegistryEntry.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/PigVariantRegistryEntry.java @@ -35,6 +35,13 @@ enum Model { */ ClientTextureAsset clientTextureAsset(); + /** + * Provides the client texture asset of the baby pig variant, which represents the texture to use. + * + * @return the baby client texture asset. + */ + ClientTextureAsset babyClientTextureAsset(); + /** * Provides the model of the pig variant. * @@ -48,6 +55,7 @@ enum Model { * The following values are required for each builder: *
      *
    • {@link #clientTextureAsset(ClientTextureAsset)}
    • + *
    • {@link #babyClientTextureAsset(ClientTextureAsset)}
    • *
    • {@link #model(Model)}
    • *
    */ @@ -65,6 +73,16 @@ interface Builder extends PigVariantRegistryEntry, RegistryBuilder @Contract(value = "_ -> this", mutates = "this") Builder clientTextureAsset(ClientTextureAsset clientTextureAsset); + /** + * Sets the client texture asset of the baby pig variant, which is the location of the texture to use. + * + * @param babyClientTextureAsset the baby client texture asset. + * @return this builder instance. + * @see PigVariantRegistryEntry#babyClientTextureAsset() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder babyClientTextureAsset(ClientTextureAsset babyClientTextureAsset); + /** * Sets the model to use for this pig variant. * diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/WolfVariantRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/WolfVariantRegistryEntry.java index 786b8bd822c7..921c533dd226 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/data/WolfVariantRegistryEntry.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/WolfVariantRegistryEntry.java @@ -34,6 +34,27 @@ public interface WolfVariantRegistryEntry { */ ClientTextureAsset tameClientTextureAsset(); + /** + * Provides the client texture asset of the wolf variant for when it is an angry baby. + * + * @return the baby angry client texture asset. + */ + ClientTextureAsset babyAngryClientTextureAsset(); + + /** + * Provides the client texture asset of the wolf variant for when it is a wild baby. + * + * @return the baby wild client texture asset. + */ + ClientTextureAsset babyWildClientTextureAsset(); + + /** + * Provides the client texture asset of the wolf variant for when it is a tame baby. + * + * @return the baby tame client texture asset. + */ + ClientTextureAsset babyTameClientTextureAsset(); + /** * A mutable builder for the {@link WolfVariantRegistryEntry} plugins may change in applicable registry events. *

    @@ -42,6 +63,9 @@ public interface WolfVariantRegistryEntry { *

  • {@link #angryClientTextureAsset(ClientTextureAsset)}
  • *
  • {@link #wildClientTextureAsset(ClientTextureAsset)}
  • *
  • {@link #tameClientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyAngryClientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyWildClientTextureAsset(ClientTextureAsset)}
  • + *
  • {@link #babyTameClientTextureAsset(ClientTextureAsset)}
  • * */ @ApiStatus.Experimental @@ -77,5 +101,35 @@ interface Builder extends WolfVariantRegistryEntry, RegistryBuilder BY_DATA = Maps.newHashMap(); - - // Paper - remove ctor (the server still uses the byte magic value) - private Instrument(final int type, final Sound sound) { - this.type = (byte) type; + Instrument(final Sound sound) { this.sound = sound; } @@ -128,10 +138,11 @@ public Sound getSound() { /** * @return The type ID of this instrument. + * @deprecated use {@link #ordinal()}, there's no meaning to this id */ - @org.jetbrains.annotations.ApiStatus.Internal // Paper + @Deprecated(since = "26.1") public byte getType() { - return this.type; + return (byte) this.ordinal(); } /** @@ -139,16 +150,11 @@ public byte getType() { * * @param type The type ID * @return The instrument + * @deprecated type is just the ordinal of the enum, no meaning in the game */ - @org.jetbrains.annotations.ApiStatus.Internal // Paper @Nullable + @Deprecated(since = "26.1") public static Instrument getByType(final byte type) { - return BY_DATA.get(type); - } - - static { - for (Instrument instrument : Instrument.values()) { - BY_DATA.put(instrument.getType(), instrument); - } + return ArrayUtils.get(values(), type); } } diff --git a/paper-api/src/main/java/org/bukkit/Material.java b/paper-api/src/main/java/org/bukkit/Material.java index 8e663e2edc0f..3e0df7b1abcd 100644 --- a/paper-api/src/main/java/org/bukkit/Material.java +++ b/paper-api/src/main/java/org/bukkit/Material.java @@ -1057,6 +1057,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla GLOWSTONE(-1), GOLD_BLOCK(-1), GOLD_ORE(-1), + GOLDEN_DANDELION(-1), GRANITE(-1), GRANITE_SLAB(-1, Slab.class), GRANITE_STAIRS(-1, Stairs.class), @@ -1425,6 +1426,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla POTTED_DEAD_BUSH(-1), POTTED_FERN(-1), POTTED_FLOWERING_AZALEA_BUSH(-1), + POTTED_GOLDEN_DANDELION(-1), POTTED_JUNGLE_SAPLING(-1), POTTED_LILY_OF_THE_VALLEY(-1), POTTED_MANGROVE_PROPAGULE(-1), diff --git a/paper-api/src/main/java/org/bukkit/NamespacedKey.java b/paper-api/src/main/java/org/bukkit/NamespacedKey.java index 57d95e22db8c..b53028683bfa 100644 --- a/paper-api/src/main/java/org/bukkit/NamespacedKey.java +++ b/paper-api/src/main/java/org/bukkit/NamespacedKey.java @@ -81,7 +81,7 @@ public NamespacedKey(@NotNull Plugin plugin, @NotNull String key) { private void validate() { Preconditions.checkArgument(this.namespace.length() + 1 + this.key.length() <= Short.MAX_VALUE, "NamespacedKey must be less than 32768 characters"); - checkError("[a-z0-9_-.]", "namespace", this.namespace, Key.checkNamespace(this.namespace)); + checkError("[a-z0-9_-.]", "namespace", this.namespace, Key.checkNamespace(this.namespace)); // note: for now we will pretend ".." is a valid namespace like adventure to not break conversion checkError("[a-z0-9_-./]", "key", this.key, Key.checkValue(this.key)); } diff --git a/paper-api/src/main/java/org/bukkit/Particle.java b/paper-api/src/main/java/org/bukkit/Particle.java index 4f1ebb38e5d7..a2e40e0185f8 100644 --- a/paper-api/src/main/java/org/bukkit/Particle.java +++ b/paper-api/src/main/java/org/bukkit/Particle.java @@ -175,6 +175,8 @@ public enum Particle implements Keyed { */ BLOCK_MARKER("block_marker", BlockData.class), COPPER_FIRE_FLAME("copper_fire_flame"), + PAUSE_MOB_GROWTH("pause_mob_growth"), + RESET_MOB_GROWTH("reset_mob_growth"), ; private final NamespacedKey key; diff --git a/paper-api/src/main/java/org/bukkit/Sound.java b/paper-api/src/main/java/org/bukkit/Sound.java index 1ba2f4969419..c98aaff3d0c8 100644 --- a/paper-api/src/main/java/org/bukkit/Sound.java +++ b/paper-api/src/main/java/org/bukkit/Sound.java @@ -1075,6 +1075,14 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound BLOCK_NOTE_BLOCK_SNARE = getSound("block.note_block.snare"); + Sound BLOCK_NOTE_BLOCK_TRUMPET = getSound("block.note_block.trumpet"); + + Sound BLOCK_NOTE_BLOCK_TRUMPET_EXPOSED = getSound("block.note_block.trumpet_exposed"); + + Sound BLOCK_NOTE_BLOCK_TRUMPET_OXIDIZED = getSound("block.note_block.trumpet_oxidized"); + + Sound BLOCK_NOTE_BLOCK_TRUMPET_WEATHERED = getSound("block.note_block.trumpet_weathered"); + Sound BLOCK_NOTE_BLOCK_XYLOPHONE = getSound("block.note_block.xylophone"); Sound BLOCK_NYLIUM_BREAK = getSound("block.nylium.break"); @@ -1739,6 +1747,48 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_AXOLOTL_SWIM = getSound("entity.axolotl.swim"); + Sound ENTITY_BABY_CAT_AMBIENT = getSound("entity.baby_cat.ambient"); + + Sound ENTITY_BABY_CAT_BEG_FOR_FOOD = getSound("entity.baby_cat.beg_for_food"); + + Sound ENTITY_BABY_CAT_DEATH = getSound("entity.baby_cat.death"); + + Sound ENTITY_BABY_CAT_EAT = getSound("entity.baby_cat.eat"); + + Sound ENTITY_BABY_CAT_HISS = getSound("entity.baby_cat.hiss"); + + Sound ENTITY_BABY_CAT_HURT = getSound("entity.baby_cat.hurt"); + + Sound ENTITY_BABY_CAT_PURR = getSound("entity.baby_cat.purr"); + + Sound ENTITY_BABY_CAT_PURREOW = getSound("entity.baby_cat.purreow"); + + Sound ENTITY_BABY_CAT_STRAY_AMBIENT = getSound("entity.baby_cat.stray_ambient"); + + Sound ENTITY_BABY_CHICKEN_AMBIENT = getSound("entity.baby_chicken.ambient"); + + Sound ENTITY_BABY_CHICKEN_DEATH = getSound("entity.baby_chicken.death"); + + Sound ENTITY_BABY_CHICKEN_HURT = getSound("entity.baby_chicken.hurt"); + + Sound ENTITY_BABY_CHICKEN_STEP = getSound("entity.baby_chicken.step"); + + Sound ENTITY_BABY_HORSE_AMBIENT = getSound("entity.baby_horse.ambient"); + + Sound ENTITY_BABY_HORSE_ANGRY = getSound("entity.baby_horse.angry"); + + Sound ENTITY_BABY_HORSE_BREATHE = getSound("entity.baby_horse.breathe"); + + Sound ENTITY_BABY_HORSE_DEATH = getSound("entity.baby_horse.death"); + + Sound ENTITY_BABY_HORSE_EAT = getSound("entity.baby_horse.eat"); + + Sound ENTITY_BABY_HORSE_HURT = getSound("entity.baby_horse.hurt"); + + Sound ENTITY_BABY_HORSE_LAND = getSound("entity.baby_horse.land"); + + Sound ENTITY_BABY_HORSE_STEP = getSound("entity.baby_horse.step"); + Sound ENTITY_BABY_NAUTILUS_AMBIENT = getSound("entity.baby_nautilus.ambient"); Sound ENTITY_BABY_NAUTILUS_AMBIENT_LAND = getSound("entity.baby_nautilus.ambient_land"); @@ -1755,6 +1805,30 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_BABY_NAUTILUS_SWIM = getSound("entity.baby_nautilus.swim"); + Sound ENTITY_BABY_PIG_AMBIENT = getSound("entity.baby_pig.ambient"); + + Sound ENTITY_BABY_PIG_DEATH = getSound("entity.baby_pig.death"); + + Sound ENTITY_BABY_PIG_EAT = getSound("entity.baby_pig.eat"); + + Sound ENTITY_BABY_PIG_HURT = getSound("entity.baby_pig.hurt"); + + Sound ENTITY_BABY_PIG_STEP = getSound("entity.baby_pig.step"); + + Sound ENTITY_BABY_WOLF_AMBIENT = getSound("entity.baby_wolf.ambient"); + + Sound ENTITY_BABY_WOLF_DEATH = getSound("entity.baby_wolf.death"); + + Sound ENTITY_BABY_WOLF_GROWL = getSound("entity.baby_wolf.growl"); + + Sound ENTITY_BABY_WOLF_HURT = getSound("entity.baby_wolf.hurt"); + + Sound ENTITY_BABY_WOLF_PANT = getSound("entity.baby_wolf.pant"); + + Sound ENTITY_BABY_WOLF_STEP = getSound("entity.baby_wolf.step"); + + Sound ENTITY_BABY_WOLF_WHINE = getSound("entity.baby_wolf.whine"); + Sound ENTITY_BAT_AMBIENT = getSound("entity.bat.ambient"); Sound ENTITY_BAT_DEATH = getSound("entity.bat.death"); @@ -1889,6 +1963,24 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_CAT_STRAY_AMBIENT = getSound("entity.cat.stray_ambient"); + Sound ENTITY_CAT_ROYAL_AMBIENT = getSound("entity.cat_royal.ambient"); + + Sound ENTITY_CAT_ROYAL_BEG_FOR_FOOD = getSound("entity.cat_royal.beg_for_food"); + + Sound ENTITY_CAT_ROYAL_DEATH = getSound("entity.cat_royal.death"); + + Sound ENTITY_CAT_ROYAL_EAT = getSound("entity.cat_royal.eat"); + + Sound ENTITY_CAT_ROYAL_HISS = getSound("entity.cat_royal.hiss"); + + Sound ENTITY_CAT_ROYAL_HURT = getSound("entity.cat_royal.hurt"); + + Sound ENTITY_CAT_ROYAL_PURR = getSound("entity.cat_royal.purr"); + + Sound ENTITY_CAT_ROYAL_PURREOW = getSound("entity.cat_royal.purreow"); + + Sound ENTITY_CAT_ROYAL_STRAY_AMBIENT = getSound("entity.cat_royal.stray_ambient"); + Sound ENTITY_CHICKEN_AMBIENT = getSound("entity.chicken.ambient"); Sound ENTITY_CHICKEN_DEATH = getSound("entity.chicken.death"); @@ -1899,6 +1991,12 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_CHICKEN_STEP = getSound("entity.chicken.step"); + Sound ENTITY_CHICKEN_PICKY_AMBIENT = getSound("entity.chicken_picky.ambient"); + + Sound ENTITY_CHICKEN_PICKY_DEATH = getSound("entity.chicken_picky.death"); + + Sound ENTITY_CHICKEN_PICKY_HURT = getSound("entity.chicken_picky.hurt"); + Sound ENTITY_COD_AMBIENT = getSound("entity.cod.ambient"); Sound ENTITY_COD_DEATH = getSound("entity.cod.death"); @@ -1955,6 +2053,14 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_COW_STEP = getSound("entity.cow.step"); + Sound ENTITY_COW_MOODY_AMBIENT = getSound("entity.cow_moody.ambient"); + + Sound ENTITY_COW_MOODY_DEATH = getSound("entity.cow_moody.death"); + + Sound ENTITY_COW_MOODY_HURT = getSound("entity.cow_moody.hurt"); + + Sound ENTITY_COW_MOODY_STEP = getSound("entity.cow_moody.step"); + Sound ENTITY_CREAKING_ACTIVATE = getSound("entity.creaking.activate"); Sound ENTITY_CREAKING_AMBIENT = getSound("entity.creaking.ambient"); @@ -2651,12 +2757,30 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ENTITY_PIG_DEATH = getSound("entity.pig.death"); + Sound ENTITY_PIG_EAT = getSound("entity.pig.eat"); + Sound ENTITY_PIG_HURT = getSound("entity.pig.hurt"); Sound ENTITY_PIG_SADDLE = getSound("entity.pig.saddle"); Sound ENTITY_PIG_STEP = getSound("entity.pig.step"); + Sound ENTITY_PIG_BIG_AMBIENT = getSound("entity.pig_big.ambient"); + + Sound ENTITY_PIG_BIG_DEATH = getSound("entity.pig_big.death"); + + Sound ENTITY_PIG_BIG_EAT = getSound("entity.pig_big.eat"); + + Sound ENTITY_PIG_BIG_HURT = getSound("entity.pig_big.hurt"); + + Sound ENTITY_PIG_MINI_AMBIENT = getSound("entity.pig_mini.ambient"); + + Sound ENTITY_PIG_MINI_DEATH = getSound("entity.pig_mini.death"); + + Sound ENTITY_PIG_MINI_EAT = getSound("entity.pig_mini.eat"); + + Sound ENTITY_PIG_MINI_HURT = getSound("entity.pig_mini.hurt"); + Sound ENTITY_PIGLIN_ADMIRING_ITEM = getSound("entity.piglin.admiring_item"); Sound ENTITY_PIGLIN_AMBIENT = getSound("entity.piglin.ambient"); @@ -3475,6 +3599,10 @@ public interface Sound extends OldEnum, Keyed, net.kyori.adventure.sound. Sound ITEM_GOAT_HORN_SOUND_7 = getSound("item.goat_horn.sound.7"); + Sound ITEM_GOLDEN_DANDELION_UNUSE = getSound("item.golden_dandelion.unuse"); + + Sound ITEM_GOLDEN_DANDELION_USE = getSound("item.golden_dandelion.use"); + Sound ITEM_HOE_TILL = getSound("item.hoe.till"); Sound ITEM_HONEY_BOTTLE_DRINK = getSound("item.honey_bottle.drink"); diff --git a/paper-api/src/main/java/org/bukkit/Tag.java b/paper-api/src/main/java/org/bukkit/Tag.java index 5fbb1ccaeb42..7e2f386ce22f 100644 --- a/paper-api/src/main/java/org/bukkit/Tag.java +++ b/paper-api/src/main/java/org/bukkit/Tag.java @@ -48,8 +48,6 @@ public interface Tag extends Keyed { Tag BAMBOO_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("bamboo_blocks"), Material.class); - Tag BAMBOO_PLANTABLE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("bamboo_plantable_on"), Material.class); - Tag BANNERS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("banners"), Material.class); Tag BARS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("bars"), Material.class); @@ -70,7 +68,9 @@ public interface Tag extends Keyed { Tag BEEHIVES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("beehives"), Material.class); - Tag BIG_DRIPLEAF_PLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("big_dripleaf_placeable"), Material.class); + Tag BENEATH_BAMBOO_PODZOL_REPLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("beneath_bamboo_podzol_replaceable"), Material.class); + + Tag BENEATH_TREE_PODZOL_REPLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("beneath_tree_podzol_replaceable"), Material.class); Tag BIRCH_LOGS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("birch_logs"), Material.class); @@ -90,6 +90,14 @@ public interface Tag extends Keyed { Tag CANDLES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("candles"), Material.class); + Tag CANNOT_REPLACE_BELOW_TREE_TRUNK = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cannot_replace_below_tree_trunk"), Material.class); + + Tag CANNOT_SUPPORT_KELP = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cannot_support_kelp"), Material.class); + + Tag CANNOT_SUPPORT_SEAGRASS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cannot_support_seagrass"), Material.class); + + Tag CANNOT_SUPPORT_SNOW_LAYER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cannot_support_snow_layer"), Material.class); + Tag CAULDRONS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cauldrons"), Material.class); Tag CAVE_VINES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("cave_vines"), Material.class); @@ -152,12 +160,14 @@ public interface Tag extends Keyed { Tag DRIPSTONE_REPLACEABLE_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("dripstone_replaceable_blocks"), Material.class); - Tag DRY_VEGETATION_MAY_PLACE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("dry_vegetation_may_place_on"), Material.class); - Tag EDIBLE_FOR_SHEEP = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("edible_for_sheep"), Material.class); Tag EMERALD_ORES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("emerald_ores"), Material.class); + Tag ENABLES_BUBBLE_COLUMN_DRAG_DOWN = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("enables_bubble_column_drag_down"), Material.class); + + Tag ENABLES_BUBBLE_COLUMN_PUSH_UP = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("enables_bubble_column_push_up"), Material.class); + Tag ENCHANTMENT_POWER_PROVIDER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("enchantment_power_provider"), Material.class); Tag ENCHANTMENT_POWER_TRANSMITTER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("enchantment_power_transmitter"), Material.class); @@ -178,6 +188,8 @@ public interface Tag extends Keyed { Tag FLOWERS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("flowers"), Material.class); + Tag FOREST_ROCK_CAN_PLACE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("forest_rock_can_place_on"), Material.class); + Tag FOXES_SPAWNABLE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("foxes_spawnable_on"), Material.class); Tag FROG_PREFER_JUMP_TO = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("frog_prefer_jump_to"), Material.class); @@ -190,14 +202,24 @@ public interface Tag extends Keyed { Tag GOLD_ORES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("gold_ores"), Material.class); + Tag GRASS_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("grass_blocks"), Material.class); + + Tag GROWS_CROPS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("grows_crops"), Material.class); + Tag GUARDED_BY_PIGLINS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("guarded_by_piglins"), Material.class); Tag HAPPY_GHAST_AVOIDS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("happy_ghast_avoids"), Material.class); Tag HOGLIN_REPELLENTS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("hoglin_repellents"), Material.class); + Tag HUGE_BROWN_MUSHROOM_CAN_PLACE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("huge_brown_mushroom_can_place_on"), Material.class); + + Tag HUGE_RED_MUSHROOM_CAN_PLACE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("huge_red_mushroom_can_place_on"), Material.class); + Tag ICE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("ice"), Material.class); + Tag ICE_SPIKE_REPLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("ice_spike_replaceable"), Material.class); + Tag IMPERMEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("impermeable"), Material.class); Tag INCORRECT_FOR_COPPER_TOOL = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("incorrect_for_copper_tool"), Material.class); @@ -264,9 +286,11 @@ public interface Tag extends Keyed { Tag MOOSHROOMS_SPAWNABLE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("mooshrooms_spawnable_on"), Material.class); + Tag MOSS_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("moss_blocks"), Material.class); + Tag MOSS_REPLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("moss_replaceable"), Material.class); - Tag MUSHROOM_GROW_BLOCK = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("mushroom_grow_block"), Material.class); + Tag MUD = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("mud"), Material.class); Tag NEEDS_DIAMOND_TOOL = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("needs_diamond_tool"), Material.class); @@ -282,6 +306,8 @@ public interface Tag extends Keyed { Tag OCCLUDES_VIBRATION_SIGNALS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("occludes_vibration_signals"), Material.class); + Tag OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("overrides_mushroom_light_requirement"), Material.class); + Tag OVERWORLD_CARVER_REPLACEABLES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("overworld_carver_replaceables"), Material.class); Tag OVERWORLD_NATURAL_LOGS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("overworld_natural_logs"), Material.class); @@ -302,6 +328,8 @@ public interface Tag extends Keyed { Tag PREVENT_MOB_SPAWNING_INSIDE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("prevent_mob_spawning_inside"), Material.class); + Tag PREVENTS_NEARBY_LEAF_DECAY = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("prevents_nearby_leaf_decay"), Material.class); + Tag RABBITS_SPAWNABLE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("rabbits_spawnable_on"), Material.class); Tag RAILS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("rails"), Material.class); @@ -328,8 +356,6 @@ public interface Tag extends Keyed { Tag SLABS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("slabs"), Material.class); - Tag SMALL_DRIPLEAF_PLACEABLE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("small_dripleaf_placeable"), Material.class); - Tag SMALL_FLOWERS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("small_flowers"), Material.class); Tag SMELTS_TO_GLASS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("smelts_to_glass"), Material.class); @@ -342,10 +368,6 @@ public interface Tag extends Keyed { Tag SNOW = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("snow"), Material.class); - Tag SNOW_LAYER_CAN_SURVIVE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("snow_layer_can_survive_on"), Material.class); - - Tag SNOW_LAYER_CANNOT_SURVIVE_ON = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("snow_layer_cannot_survive_on"), Material.class); - Tag SOUL_FIRE_BASE_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("soul_fire_base_blocks"), Material.class); Tag SOUL_SPEED_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("soul_speed_blocks"), Material.class); @@ -366,6 +388,72 @@ public interface Tag extends Keyed { Tag STRIDER_WARM_BLOCKS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("strider_warm_blocks"), Material.class); + Tag SUBSTRATE_OVERWORLD = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("substrate_overworld"), Material.class); + + Tag SUPPORT_OVERRIDE_CACTUS_FLOWER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("support_override_cactus_flower"), Material.class); + + Tag SUPPORT_OVERRIDE_SNOW_LAYER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("support_override_snow_layer"), Material.class); + + Tag SUPPORTS_AZALEA = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_azalea"), Material.class); + + Tag SUPPORTS_BAMBOO = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_bamboo"), Material.class); + + Tag SUPPORTS_BIG_DRIPLEAF = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_big_dripleaf"), Material.class); + + Tag SUPPORTS_CACTUS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_cactus"), Material.class); + + Tag SUPPORTS_CHORUS_FLOWER = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_chorus_flower"), Material.class); + + Tag SUPPORTS_CHORUS_PLANT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_chorus_plant"), Material.class); + + Tag SUPPORTS_COCOA = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_cocoa"), Material.class); + + Tag SUPPORTS_CRIMSON_FUNGUS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_crimson_fungus"), Material.class); + + Tag SUPPORTS_CRIMSON_ROOTS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_crimson_roots"), Material.class); + + Tag SUPPORTS_CROPS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_crops"), Material.class); + + Tag SUPPORTS_DRY_VEGETATION = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_dry_vegetation"), Material.class); + + Tag SUPPORTS_FROGSPAWN = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_frogspawn"), Material.class); + + Tag SUPPORTS_HANGING_MANGROVE_PROPAGULE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_hanging_mangrove_propagule"), Material.class); + + Tag SUPPORTS_LILY_PAD = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_lily_pad"), Material.class); + + Tag SUPPORTS_MANGROVE_PROPAGULE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_mangrove_propagule"), Material.class); + + Tag SUPPORTS_MELON_STEM = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_melon_stem"), Material.class); + + Tag SUPPORTS_MELON_STEM_FRUIT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_melon_stem_fruit"), Material.class); + + Tag SUPPORTS_NETHER_SPROUTS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_nether_sprouts"), Material.class); + + Tag SUPPORTS_NETHER_WART = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_nether_wart"), Material.class); + + Tag SUPPORTS_PUMPKIN_STEM = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_pumpkin_stem"), Material.class); + + Tag SUPPORTS_PUMPKIN_STEM_FRUIT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_pumpkin_stem_fruit"), Material.class); + + Tag SUPPORTS_SMALL_DRIPLEAF = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_small_dripleaf"), Material.class); + + Tag SUPPORTS_STEM_CROPS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_stem_crops"), Material.class); + + Tag SUPPORTS_STEM_FRUIT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_stem_fruit"), Material.class); + + Tag SUPPORTS_SUGAR_CANE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_sugar_cane"), Material.class); + + Tag SUPPORTS_SUGAR_CANE_ADJACENTLY = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_sugar_cane_adjacently"), Material.class); + + Tag SUPPORTS_VEGETATION = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_vegetation"), Material.class); + + Tag SUPPORTS_WARPED_FUNGUS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_warped_fungus"), Material.class); + + Tag SUPPORTS_WARPED_ROOTS = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_warped_roots"), Material.class); + + Tag SUPPORTS_WITHER_ROSE = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("supports_wither_rose"), Material.class); + Tag SWORD_EFFICIENT = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("sword_efficient"), Material.class); Tag SWORD_INSTANTLY_MINES = Bukkit.getTag(REGISTRY_BLOCKS, NamespacedKey.minecraft("sword_instantly_mines"), Material.class); @@ -478,8 +566,12 @@ public interface Tag extends Keyed { Tag ITEMS_CANDLES = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("candles"), Material.class); + Tag ITEMS_CAT_COLLAR_DYES = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("cat_collar_dyes"), Material.class); + Tag ITEMS_CAT_FOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("cat_food"), Material.class); + Tag ITEMS_CAULDRON_CAN_REMOVE_DYE = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("cauldron_can_remove_dye"), Material.class); + Tag ITEMS_CHAINS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("chains"), Material.class); Tag ITEMS_CHERRY_LOGS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("cherry_logs"), Material.class); @@ -538,7 +630,7 @@ public interface Tag extends Keyed { Tag ITEMS_DUPLICATES_ALLAYS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("duplicates_allays"), Material.class); - Tag ITEMS_DYEABLE = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("dyeable"), Material.class); + Tag ITEMS_DYES = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("dyes"), Material.class); Tag ITEMS_EGGS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("eggs"), Material.class); @@ -612,6 +704,8 @@ public interface Tag extends Keyed { Tag ITEMS_GOLD_TOOL_MATERIALS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("gold_tool_materials"), Material.class); + Tag ITEMS_GRASS_BLOCKS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("grass_blocks"), Material.class); + Tag ITEMS_HANGING_SIGNS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("hanging_signs"), Material.class); Tag ITEMS_HAPPY_GHAST_FOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("happy_ghast_food"), Material.class); @@ -658,12 +752,22 @@ public interface Tag extends Keyed { Tag ITEMS_LOGS_THAT_BURN = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("logs_that_burn"), Material.class); + Tag ITEMS_LOOM_DYES = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("loom_dyes"), Material.class); + + Tag ITEMS_LOOM_PATTERNS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("loom_patterns"), Material.class); + Tag ITEMS_MANGROVE_LOGS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("mangrove_logs"), Material.class); Tag ITEMS_MAP_INVISIBILITY_EQUIPMENT = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("map_invisibility_equipment"), Material.class); Tag ITEMS_MEAT = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("meat"), Material.class); + Tag ITEMS_METAL_NUGGETS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("metal_nuggets"), Material.class); + + Tag ITEMS_MOSS_BLOCKS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("moss_blocks"), Material.class); + + Tag ITEMS_MUD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("mud"), Material.class); + Tag ITEMS_NAUTILUS_BUCKET_FOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("nautilus_bucket_food"), Material.class); Tag ITEMS_NAUTILUS_FOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("nautilus_food"), Material.class); @@ -802,6 +906,8 @@ public interface Tag extends Keyed { Tag ITEMS_WITHER_SKELETON_DISLIKED_WEAPONS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("wither_skeleton_disliked_weapons"), Material.class); + Tag ITEMS_WOLF_COLLAR_DYES = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("wolf_collar_dyes"), Material.class); + Tag ITEMS_WOLF_FOOD = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("wolf_food"), Material.class); Tag ITEMS_WOODEN_BUTTONS = Bukkit.getTag(REGISTRY_ITEMS, NamespacedKey.minecraft("wooden_buttons"), Material.class); @@ -830,8 +936,16 @@ public interface Tag extends Keyed { String REGISTRY_FLUIDS = "fluids"; + Tag FLUIDS_BUBBLE_COLUMN_CAN_OCCUPY = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("bubble_column_can_occupy"), Fluid.class); + Tag FLUIDS_LAVA = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("lava"), Fluid.class); + Tag FLUIDS_SUPPORTS_FROGSPAWN = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("supports_frogspawn"), Fluid.class); + + Tag FLUIDS_SUPPORTS_LILY_PAD = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("supports_lily_pad"), Fluid.class); + + Tag FLUIDS_SUPPORTS_SUGAR_CANE_ADJACENTLY = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("supports_sugar_cane_adjacently"), Fluid.class); + Tag FLUIDS_WATER = Bukkit.getTag(REGISTRY_FLUIDS, NamespacedKey.minecraft("water"), Fluid.class); String REGISTRY_ENTITY_TYPES = "entity_types"; @@ -870,6 +984,8 @@ public interface Tag extends Keyed { Tag ENTITY_TYPES_CANDIDATE_FOR_IRON_GOLEM_GIFT = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("candidate_for_iron_golem_gift"), EntityType.class); + Tag ENTITY_TYPES_CANNOT_BE_AGE_LOCKED = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("cannot_be_age_locked"), EntityType.class); + Tag ENTITY_TYPES_CANNOT_BE_PUSHED_ONTO_BOATS = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("cannot_be_pushed_onto_boats"), EntityType.class); Tag ENTITY_TYPES_DEFLECTS_PROJECTILES = Bukkit.getTag(REGISTRY_ENTITY_TYPES, NamespacedKey.minecraft("deflects_projectiles"), EntityType.class); @@ -940,18 +1056,54 @@ public interface Tag extends Keyed { Tag GAME_EVENT_WARDEN_CAN_LISTEN = Bukkit.getTag(REGISTRY_GAME_EVENTS, NamespacedKey.minecraft("warden_can_listen"), GameEvent.class); // End generate - Tag + // /** - * @deprecated {@link #WOOL_CARPETS}. + * @deprecated replaced by {@link #WOOL_CARPETS}. */ - @Deprecated(since = "1.19") + @Deprecated(since = "1.19", forRemoval = true) Tag CARPETS = WOOL_CARPETS; + /** + * @deprecated replaced by {@link #CANNOT_SUPPORT_SNOW_LAYER} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag SNOW_LAYER_CANNOT_SURVIVE_ON = CANNOT_SUPPORT_SNOW_LAYER; + /** + * @deprecated replaced by {@link #SUPPORT_OVERRIDE_SNOW_LAYER} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag SNOW_LAYER_CAN_SURVIVE_ON = SUPPORT_OVERRIDE_SNOW_LAYER; + /** + * @deprecated partially replaced by {@link #OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag MUSHROOM_GROW_BLOCK = OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT; + /** + * @deprecated replaced by {@link #SUPPORTS_SMALL_DRIPLEAF} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag SMALL_DRIPLEAF_PLACEABLE = SUPPORTS_SMALL_DRIPLEAF; + /** + * @deprecated replaced by {@link #SUPPORTS_BIG_DRIPLEAF} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag BIG_DRIPLEAF_PLACEABLE = SUPPORTS_BIG_DRIPLEAF; + /** + * @deprecated replaced by {@link #SUPPORTS_BAMBOO} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag BAMBOO_PLANTABLE_ON = SUPPORTS_BAMBOO; + /** + * @deprecated replaced by {@link #SUPPORTS_DRY_VEGETATION} + */ + @Deprecated(since = "26.1", forRemoval = true) + Tag DRY_VEGETATION_MAY_PLACE_ON = SUPPORTS_DRY_VEGETATION; /** * Vanilla block tag representing all blocks which dead bushes may be placed on. * - * @deprecated partially replaced by {@link #DRY_VEGETATION_MAY_PLACE_ON} + * @deprecated partially replaced by {@link #SUPPORTS_DRY_VEGETATION} */ @Deprecated(since = "1.21.5", forRemoval = true) - Tag DEAD_BUSH_MAY_PLACE_ON = DRY_VEGETATION_MAY_PLACE_ON; + Tag DEAD_BUSH_MAY_PLACE_ON = SUPPORTS_DRY_VEGETATION; /** * @deprecated replaced by {@link #TRIGGERS_AMBIENT_DESERT_DRY_VEGETATION_BLOCK_SOUNDS} */ @@ -961,23 +1113,23 @@ public interface Tag extends Keyed { * Vanilla block tag representing all blocks that are replaceable by * dripstone. * - * @deprecated use {@link #DRIPSTONE_REPLACEABLE_BLOCKS} + * @deprecated replaced by {@link #DRIPSTONE_REPLACEABLE_BLOCKS} */ @Deprecated(since = "1.21.4", forRemoval = true) Tag DRIPSTONE_REPLACEABLE = DRIPSTONE_REPLACEABLE_BLOCKS; /** * Vanilla item tag representing all piglin food. * - * @deprecated use {@link #ITEMS_PIGLIN_FOOD} + * @deprecated replaced by {@link #ITEMS_PIGLIN_FOOD} */ - @Deprecated(since = "1.20.5") + @Deprecated(since = "1.20.5", forRemoval = true) Tag PIGLIN_FOOD = ITEMS_PIGLIN_FOOD; /** * Vanilla item tag representing all fox food. * - * @deprecated use {@link #ITEMS_FOX_FOOD} + * @deprecated replaced by {@link #ITEMS_FOX_FOOD} */ - @Deprecated(since = "1.20.5") + @Deprecated(since = "1.20.5", forRemoval = true) Tag FOX_FOOD = ITEMS_FOX_FOOD; /** * Vanilla item tag representing all furnace materials. @@ -989,7 +1141,7 @@ public interface Tag extends Keyed { /** * Vanilla item tag representing all items which modify note block sounds when placed on top. * - * @deprecated use {@link #ITEMS_NOTEBLOCK_TOP_INSTRUMENTS} + * @deprecated replaced by {@link #ITEMS_NOTEBLOCK_TOP_INSTRUMENTS} */ @Deprecated(since = "1.21.4", forRemoval = true) Tag ITEMS_NOTE_BLOCK_TOP_INSTRUMENTS = ITEMS_NOTEBLOCK_TOP_INSTRUMENTS; @@ -1005,16 +1157,18 @@ public interface Tag extends Keyed { /** * Vanilla item tag representing all items which tempt axolotls. * - * @deprecated use {@link #ITEMS_AXOLOTL_FOOD} + * @deprecated replaced by {@link #ITEMS_AXOLOTL_FOOD} */ - @Deprecated(since = "1.20.5") + @Deprecated(since = "1.20.5", forRemoval = true) Tag AXOLOTL_TEMPT_ITEMS = ITEMS_AXOLOTL_FOOD; /** * Vanilla tag representing entities which deflect arrows. - * @deprecated use {@link #ENTITY_TYPES_DEFLECTS_PROJECTILES} + * + * @deprecated replaced by {@link #ENTITY_TYPES_DEFLECTS_PROJECTILES} */ - @Deprecated(since = "1.20.5") + @Deprecated(since = "1.20.5", forRemoval = true) Tag ENTITY_TYPES_DEFLECTS_ARROWS = ENTITY_TYPES_DEFLECTS_PROJECTILES; + // /** * Returns whether or not this tag has an entry for the specified item. diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java index b202bdb84bae..ec61e991174a 100644 --- a/paper-api/src/main/java/org/bukkit/World.java +++ b/paper-api/src/main/java/org/bukkit/World.java @@ -1809,7 +1809,7 @@ default RayTraceResult rayTraceEntities(@NotNull Location start, @NotNull Vector */ @Nullable default RayTraceResult rayTraceEntities(@NotNull Location start, @NotNull Vector direction, double maxDistance, @Nullable Predicate filter) { - return this.rayTraceEntities(start, direction, maxDistance, 0.0D, filter); + return this.rayTraceEntities(start, direction, maxDistance, 0.0, filter); } /** @@ -2051,7 +2051,7 @@ default boolean setSpawnLocation(int x, int y, int z) { } /** - * Gets the relative in-game time of this world. + * Gets the relative in-game time of this world, or {@code 0} if this world does not have a world clock. *

    * The relative time is analogous to hours * 1000 * @@ -2076,7 +2076,7 @@ default boolean setSpawnLocation(int x, int y, int z) { public void setTime(long time); /** - * Gets the full in-game time on this world + * Gets the full in-game time on this world, or {@code 0} if this world does not have a world clock. * * @return The current absolute time * @see #getTime() Returns a relative time of this world @@ -2091,7 +2091,10 @@ default boolean setSpawnLocation(int x, int y, int z) { * * @param time The new absolute time to set this world to * @see #setTime(long) Sets the relative time of this world + * @deprecated all overworlds share the same world clock by default now + * @throws IllegalArgumentException if this world does not have a world clock (e.g. the nether) */ + @Deprecated // TODO world clock API with links to it public void setFullTime(long time); // Paper start diff --git a/paper-api/src/main/java/org/bukkit/WorldBorder.java b/paper-api/src/main/java/org/bukkit/WorldBorder.java index 10e69cab2068..0f2f0d1589e9 100644 --- a/paper-api/src/main/java/org/bukkit/WorldBorder.java +++ b/paper-api/src/main/java/org/bukkit/WorldBorder.java @@ -36,7 +36,7 @@ public interface WorldBorder { * * @param newSize The new size of the border. * - * @throws IllegalArgumentException if newSize is less than 1.0D or greater than {@link #getMaxSize()} + * @throws IllegalArgumentException if newSize is less than 1.0 or greater than {@link #getMaxSize()} * @see #changeSize(double, long) */ void setSize(double newSize); @@ -47,7 +47,7 @@ public interface WorldBorder { * @param newSize The new side length of the border. * @param ticks The time in ticks in which the border grows or shrinks from the previous size to that being set. * - * @throws IllegalArgumentException if newSize is less than 1.0D or greater than {@link #getMaxSize()} + * @throws IllegalArgumentException if newSize is less than 1.0 or greater than {@link #getMaxSize()} * @throws IllegalArgumentException if ticks is out of range * @see #setSize(double) */ @@ -64,7 +64,7 @@ public interface WorldBorder { */ @Deprecated(since = "1.21.11", forRemoval = true) default void setSize(double newSize, long seconds) { - this.changeSize(Math.clamp(newSize, 1.0D, this.getMaxSize()), Tick.tick().fromDuration(Duration.ofSeconds(seconds))); + this.changeSize(Math.clamp(newSize, 1.0, this.getMaxSize()), Tick.tick().fromDuration(Duration.ofSeconds(seconds))); } /** @@ -74,7 +74,7 @@ default void setSize(double newSize, long seconds) { * @param unit The time unit. * @param time The time in which the border grows or shrinks from the previous size to that being set. * - * @throws IllegalArgumentException if newSize is less than 1.0D or greater than {@link #getMaxSize()} + * @throws IllegalArgumentException if newSize is less than 1.0 or greater than {@link #getMaxSize()} * @throws IllegalArgumentException if time is out of range once converted in ticks * @deprecated Use {@link #changeSize(double, long)} instead */ diff --git a/paper-api/src/main/java/org/bukkit/block/Block.java b/paper-api/src/main/java/org/bukkit/block/Block.java index fbee4ab2faae..5c75b3d049f2 100644 --- a/paper-api/src/main/java/org/bukkit/block/Block.java +++ b/paper-api/src/main/java/org/bukkit/block/Block.java @@ -232,18 +232,16 @@ public static int getBlockKeyZ(long packed) { } // Paper end - // Paper start - add isValidTool /** * Checks if the itemstack is a valid tool to * break the block with * - * @param itemStack The (tool) itemstack + * @param tool The tool * @return whether the block will drop items * @deprecated partially replaced by {@link Block#isPreferredTool(ItemStack)} */ @Deprecated(since = "1.21", forRemoval = true) // Paper - boolean isValidTool(@NotNull ItemStack itemStack); - // Paper end - add isValidTool + boolean isValidTool(@NotNull ItemStack tool); /** * Gets the Location of the block @@ -438,11 +436,18 @@ public static int getBlockKeyZ(long packed) { int getBlockPower(@NotNull BlockFace face); /** - * Returns the redstone power being provided to this block + * Returns the redstone power being provided to this block. + *

    + * Equivalent to: + * {@snippet lang="java" : + * getBlockPower(BlockFace.SELF); + * } * * @return The power level. */ - int getBlockPower(); + default int getBlockPower() { + return this.getBlockPower(BlockFace.SELF); + } /** * Checks if this block is empty. diff --git a/paper-api/src/main/java/org/bukkit/block/BlockType.java b/paper-api/src/main/java/org/bukkit/block/BlockType.java index dc2d24162deb..0e42965a729f 100644 --- a/paper-api/src/main/java/org/bukkit/block/BlockType.java +++ b/paper-api/src/main/java/org/bukkit/block/BlockType.java @@ -1024,6 +1024,8 @@ interface Typed extends BlockType { BlockType.Typed GOLD_ORE = getBlockType("gold_ore"); + BlockType.Typed GOLDEN_DANDELION = getBlockType("golden_dandelion"); + BlockType.Typed GRANITE = getBlockType("granite"); BlockType.Typed GRANITE_SLAB = getBlockType("granite_slab"); @@ -1760,6 +1762,8 @@ interface Typed extends BlockType { BlockType.Typed POTTED_FLOWERING_AZALEA_BUSH = getBlockType("potted_flowering_azalea_bush"); + BlockType.Typed POTTED_GOLDEN_DANDELION = getBlockType("potted_golden_dandelion"); + BlockType.Typed POTTED_JUNGLE_SAPLING = getBlockType("potted_jungle_sapling"); BlockType.Typed POTTED_LILY_OF_THE_VALLEY = getBlockType("potted_lily_of_the_valley"); diff --git a/paper-api/src/main/java/org/bukkit/entity/Cat.java b/paper-api/src/main/java/org/bukkit/entity/Cat.java index b8ac85e471f1..e3f49d5030ca 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Cat.java +++ b/paper-api/src/main/java/org/bukkit/entity/Cat.java @@ -2,9 +2,11 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import java.util.Locale; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import java.util.Locale; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import org.bukkit.DyeColor; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; @@ -32,6 +34,21 @@ public interface Cat extends Tameable, Sittable, io.papermc.paper.entity.CollarC */ public void setCatType(@NotNull Type type); + /** + * Get the sound variant of this cat. + * + * @return cat sound variant + */ + @NotNull + SoundVariant getSoundVariant(); + + /** + * Set the sound variant of this cat. + * + * @param variant cat sound variant + */ + void setSoundVariant(@NotNull SoundVariant variant); + /** * Get the collar color of this cat * @@ -107,6 +124,23 @@ static Type[] values() { } } + /** + * Represents the sound variant of a cat. + */ + interface SoundVariant extends Keyed { + + // Start generate - CatSoundVariant + SoundVariant CLASSIC = getSoundVariant("classic"); + + SoundVariant ROYAL = getSoundVariant("royal"); + // End generate - CatSoundVariant + + @NotNull + private static SoundVariant getSoundVariant(final @NotNull @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.CAT_SOUND_VARIANT).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + } + /** * Sets if the cat is lying down. * This is visual and does not affect the behaviour of the cat. diff --git a/paper-api/src/main/java/org/bukkit/entity/Chicken.java b/paper-api/src/main/java/org/bukkit/entity/Chicken.java index 14c2df2916fe..e0f9c37e7a23 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Chicken.java +++ b/paper-api/src/main/java/org/bukkit/entity/Chicken.java @@ -2,6 +2,8 @@ import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.jspecify.annotations.NullMarked; @@ -26,6 +28,20 @@ public interface Chicken extends Animals { */ void setVariant(Variant variant); + /** + * Get the sound variant of this chicken. + * + * @return chicken sound variant + */ + SoundVariant getSoundVariant(); + + /** + * Set the sound variant of this chicken. + * + * @param variant chicken sound variant + */ + void setSoundVariant(SoundVariant variant); + /** * Gets if this chicken was spawned as a chicken jockey. * @@ -71,4 +87,20 @@ private static Variant getVariant(String key) { return RegistryAccess.registryAccess().getRegistry(RegistryKey.CHICKEN_VARIANT).getOrThrow(NamespacedKey.minecraft(key)); } } + + /** + * Represents the sound variant of a chicken. + */ + interface SoundVariant extends Keyed { + + // Start generate - ChickenSoundVariant + SoundVariant CLASSIC = getSoundVariant("classic"); + + SoundVariant PICKY = getSoundVariant("picky"); + // End generate - ChickenSoundVariant + + private static SoundVariant getSoundVariant(final @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.CHICKEN_SOUND_VARIANT).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + } } diff --git a/paper-api/src/main/java/org/bukkit/entity/Cow.java b/paper-api/src/main/java/org/bukkit/entity/Cow.java index 44877f12cf5e..2e1ef0955d9e 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Cow.java +++ b/paper-api/src/main/java/org/bukkit/entity/Cow.java @@ -2,6 +2,8 @@ import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.jspecify.annotations.NullMarked; @@ -26,6 +28,20 @@ public interface Cow extends AbstractCow { */ void setVariant(Variant variant); + /** + * Get the sound variant of this cow. + * + * @return cow sound variant + */ + SoundVariant getSoundVariant(); + + /** + * Set the sound variant of this cow. + * + * @param variant cow sound variant + */ + void setSoundVariant(SoundVariant variant); + /** * Represents the variant of a cow. */ @@ -43,4 +59,20 @@ private static Variant getVariant(String key) { return RegistryAccess.registryAccess().getRegistry(RegistryKey.COW_VARIANT).getOrThrow(NamespacedKey.minecraft(key)); } } + + /** + * Represents the sound variant of a cow. + */ + interface SoundVariant extends Keyed { + + // Start generate - CowSoundVariant + SoundVariant CLASSIC = getSoundVariant("classic"); + + SoundVariant MOODY = getSoundVariant("moody"); + // End generate - CowSoundVariant + + private static SoundVariant getSoundVariant(final @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.COW_SOUND_VARIANT).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + } } diff --git a/paper-api/src/main/java/org/bukkit/entity/Pig.java b/paper-api/src/main/java/org/bukkit/entity/Pig.java index 24a4b588bbda..c49a9ec606dc 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Pig.java +++ b/paper-api/src/main/java/org/bukkit/entity/Pig.java @@ -2,6 +2,8 @@ import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.jspecify.annotations.NullMarked; @@ -26,6 +28,20 @@ public interface Pig extends Steerable, Vehicle { */ void setVariant(Variant variant); + /** + * Get the sound variant of this pig. + * + * @return pig sound variant + */ + SoundVariant getSoundVariant(); + + /** + * Set the sound variant of this pig. + * + * @param variant pig sound variant + */ + void setSoundVariant(SoundVariant variant); + /** * Represents the variant of a pig. */ @@ -43,4 +59,22 @@ private static Variant getVariant(String key) { return RegistryAccess.registryAccess().getRegistry(RegistryKey.PIG_VARIANT).getOrThrow(NamespacedKey.minecraft(key)); } } + + /** + * Represents the sound variant of a pig. + */ + interface SoundVariant extends Keyed { + + // Start generate - PigSoundVariant + SoundVariant BIG = getSoundVariant("big"); + + SoundVariant CLASSIC = getSoundVariant("classic"); + + SoundVariant MINI = getSoundVariant("mini"); + // End generate - PigSoundVariant + + private static SoundVariant getSoundVariant(final @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.PIG_SOUND_VARIANT).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + } } diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 26d9139886d8..5fb337eb2784 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -17,6 +17,7 @@ import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.object.PlayerHeadObjectContents; +import org.apache.commons.lang3.ArrayUtils; import org.bukkit.BanEntry; import org.bukkit.DyeColor; import org.bukkit.Effect; @@ -648,7 +649,7 @@ default void setBedSpawnLocation(@Nullable Location location, boolean force) { */ @Deprecated(since = "1.6.2") default void playNote(Location loc, byte instrument, byte note) { - this.playNote(loc, Instrument.getByType(instrument), new Note(note)); + this.playNote(loc, ArrayUtils.get(Instrument.values(), instrument), new Note(note)); } /** @@ -1794,15 +1795,14 @@ public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, ne * * @param time The current player's perceived time or the player's time * offset from the server time. - * @param relative When true the player time is kept relative to its world - * time. + * @param tickTime if true, the player time keeps ticking up relative to its world time. */ - public void setPlayerTime(long time, boolean relative); + public void setPlayerTime(long time, boolean tickTime); /** * Returns the player's current timestamp. * - * @return The player's time + * @return The player's time, or {@code 0} if the current world does not have a world clock. */ public long getPlayerTime(); diff --git a/paper-api/src/main/java/org/bukkit/event/block/BlockMultiPlaceEvent.java b/paper-api/src/main/java/org/bukkit/event/block/BlockMultiPlaceEvent.java index 0df9dfa44dcc..7f417d5b9f7f 100644 --- a/paper-api/src/main/java/org/bukkit/event/block/BlockMultiPlaceEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/block/BlockMultiPlaceEvent.java @@ -18,18 +18,18 @@ */ public class BlockMultiPlaceEvent extends BlockPlaceEvent { - private final List states; + private final List replacedStates; @ApiStatus.Internal @Deprecated(forRemoval = true) - public BlockMultiPlaceEvent(@NotNull List states, @NotNull Block clicked, @NotNull ItemStack itemInHand, @NotNull Player thePlayer, boolean canBuild) { - this(states, clicked, itemInHand, thePlayer, canBuild, org.bukkit.inventory.EquipmentSlot.HAND); + public BlockMultiPlaceEvent(@NotNull List replacedStates, @NotNull Block clicked, @NotNull ItemStack itemInHand, @NotNull Player thePlayer, boolean canBuild) { + this(replacedStates, clicked, itemInHand, thePlayer, canBuild, org.bukkit.inventory.EquipmentSlot.HAND); } @ApiStatus.Internal - public BlockMultiPlaceEvent(@NotNull List states, @NotNull Block clicked, @NotNull ItemStack itemInHand, @NotNull Player thePlayer, boolean canBuild, @NotNull org.bukkit.inventory.EquipmentSlot hand) { - super(states.get(0).getBlock(), states.get(0), clicked, itemInHand, thePlayer, canBuild, hand); - this.states = ImmutableList.copyOf(states); + public BlockMultiPlaceEvent(@NotNull List replacedStates, @NotNull Block clicked, @NotNull ItemStack itemInHand, @NotNull Player thePlayer, boolean canBuild, @NotNull org.bukkit.inventory.EquipmentSlot hand) { + super(replacedStates.getFirst().getBlock(), replacedStates.getFirst(), clicked, itemInHand, thePlayer, canBuild, hand); + this.replacedStates = ImmutableList.copyOf(replacedStates); } /** @@ -41,6 +41,6 @@ public BlockMultiPlaceEvent(@NotNull List states, @NotNull Block cli */ @NotNull public List getReplacedBlockStates() { - return this.states; + return this.replacedStates; } } diff --git a/paper-api/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java b/paper-api/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java index 81dd17b033ea..394ae727e3ee 100644 --- a/paper-api/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/block/BlockPlaceEvent.java @@ -22,7 +22,7 @@ public class BlockPlaceEvent extends BlockEvent implements Cancellable { protected Block placedAgainst; protected ItemStack itemInHand; protected Player player; - protected BlockState replacedBlockState; + protected BlockState replacedState; protected boolean canBuild; protected EquipmentSlot hand; @@ -30,17 +30,17 @@ public class BlockPlaceEvent extends BlockEvent implements Cancellable { @ApiStatus.Internal @Deprecated(since = "1.9", forRemoval = true) - public BlockPlaceEvent(@NotNull final Block placedBlock, @NotNull final BlockState replacedBlockState, @NotNull final Block placedAgainst, @NotNull final ItemStack itemInHand, @NotNull final Player thePlayer, final boolean canBuild) { - this(placedBlock, replacedBlockState, placedAgainst, itemInHand, thePlayer, canBuild, EquipmentSlot.HAND); + public BlockPlaceEvent(@NotNull final Block placedBlock, @NotNull final BlockState replacedState, @NotNull final Block placedAgainst, @NotNull final ItemStack itemInHand, @NotNull final Player thePlayer, final boolean canBuild) { + this(placedBlock, replacedState, placedAgainst, itemInHand, thePlayer, canBuild, EquipmentSlot.HAND); } @ApiStatus.Internal - public BlockPlaceEvent(@NotNull final Block placedBlock, @NotNull final BlockState replacedBlockState, @NotNull final Block placedAgainst, @NotNull final ItemStack itemInHand, @NotNull final Player thePlayer, final boolean canBuild, @NotNull final EquipmentSlot hand) { + public BlockPlaceEvent(@NotNull final Block placedBlock, @NotNull final BlockState replacedState, @NotNull final Block placedAgainst, @NotNull final ItemStack itemInHand, @NotNull final Player thePlayer, final boolean canBuild, @NotNull final EquipmentSlot hand) { super(placedBlock); this.placedAgainst = placedAgainst; this.itemInHand = itemInHand; this.player = thePlayer; - this.replacedBlockState = replacedBlockState; + this.replacedState = replacedState; this.canBuild = canBuild; this.hand = hand; } @@ -95,7 +95,7 @@ public Block getBlockPlaced() { */ @NotNull public BlockState getBlockReplacedState() { - return this.replacedBlockState; + return this.replacedState; } /** diff --git a/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java b/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java index 0a9134e7e2fc..ffcc09589e24 100644 --- a/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java @@ -11,6 +11,7 @@ *

    * If the event is cancelled the time will not change. */ +// TODO - snapshot - 26.1 API needed for clock! public class TimeSkipEvent extends WorldEvent implements Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); diff --git a/paper-api/src/main/java/org/bukkit/inventory/ItemType.java b/paper-api/src/main/java/org/bukkit/inventory/ItemType.java index d1a5e35ccc6e..e0a19bc5c31b 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/ItemType.java +++ b/paper-api/src/main/java/org/bukkit/inventory/ItemType.java @@ -1218,6 +1218,8 @@ interface Typed extends ItemType { ItemType.Typed GOLDEN_CHESTPLATE = getItemType("golden_chestplate"); + ItemType.Typed GOLDEN_DANDELION = getItemType("golden_dandelion"); + ItemType.Typed GOLDEN_HELMET = getItemType("golden_helmet"); ItemType.Typed GOLDEN_HOE = getItemType("golden_hoe"); diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java index 08fd7877df04..1957d8d94f71 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java @@ -1,13 +1,15 @@ package org.bukkit.inventory.meta; import com.google.common.collect.Multimap; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.ItemAdventurePredicate; +import io.papermc.paper.registry.keys.tags.DamageTypeTagKeys; +import io.papermc.paper.registry.set.RegistryKeySet; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; -import io.papermc.paper.datacomponent.DataComponentType; -import io.papermc.paper.datacomponent.DataComponentTypes; -import io.papermc.paper.datacomponent.item.ItemAdventurePredicate; import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; import org.bukkit.Tag; @@ -29,7 +31,6 @@ import org.bukkit.inventory.meta.components.UseCooldownComponent; import org.bukkit.inventory.meta.tags.CustomItemTagContainer; import org.bukkit.persistence.PersistentDataHolder; -import org.bukkit.tag.DamageTypeTags; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -634,8 +635,7 @@ default void displayName(final net.kyori.adventure.text.@Nullable Component disp * or lava. * * @return fire_resistant - * @deprecated use {@link #getDamageResistant()} and - * {@link DamageTypeTags#IS_FIRE} + * @deprecated use {@link #getDamageResistance()} and check if it matches any {@link DamageTypeTagKeys#IS_FIRE fire damage type} */ @Deprecated(since = "1.21.2") boolean isFireResistant(); @@ -645,8 +645,7 @@ default void displayName(final net.kyori.adventure.text.@Nullable Component disp * or lava. * * @param fireResistant fire_resistant - * @deprecated use {@link #setDamageResistant(org.bukkit.Tag)} and - * {@link DamageTypeTags#IS_FIRE} + * @deprecated use {@link #setDamageResistance(RegistryKeySet)} with {@link DamageTypeTagKeys#IS_FIRE} */ @Deprecated(since = "1.21.2") void setFireResistant(boolean fireResistant); @@ -662,12 +661,11 @@ default void displayName(final net.kyori.adventure.text.@Nullable Component disp * Gets the type of damage this item will be resistant to when in entity * form. * - * Plugins should check {@link #hasDamageResistant()} before calling this - * method. - * - * @return damage type + * @return damage type tag + * @deprecated use {@link #getDamageResistance()} */ @Nullable + @Deprecated(since = "26.1") Tag getDamageResistant(); /** @@ -675,9 +673,27 @@ default void displayName(final net.kyori.adventure.text.@Nullable Component disp * form. * * @param tag the tag, or null to clear + * @deprecated use {@link #setDamageResistance(RegistryKeySet)} */ + @Deprecated(since = "26.1") void setDamageResistant(@Nullable Tag tag); + /** + * Gets the type of damage this item will be resistant to when in entity + * form. + * + * @return the registry key set holding the respective damage types. + */ + @Nullable RegistryKeySet getDamageResistance(); + + /** + * Sets the type of damage this item will be resistant to when in entity + * form. + * + * @param types the registry key set, or null to clear + */ + void setDamageResistance(@Nullable RegistryKeySet types); + /** * Gets if the max_stack_size is set. * @@ -1039,9 +1055,9 @@ default void displayName(final net.kyori.adventure.text.@Nullable Component disp * assert itemStack.isSimilar(recreatedItemStack); // Should be true* * *

    - * *Components not represented or explicitly overridden by this ItemMeta instance - * will not be included in the resulting string and therefore may result in ItemStacks - * that do not match exactly. For example, if {@link #setDisplayName(String)} + * *Components not represented or explicitly overridden by this ItemMeta instance and + * transient components will not be included in the resulting string and therefore may + * result in ItemStacks that do not match exactly. For example, if {@link #setDisplayName(String)} * is not set, then the custom name component will not be included. Or if this ItemMeta * is a PotionMeta, it will not include any components related to lodestone compasses, * banners, or books, etc., only components modifiable by a PotionMeta instance. diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java b/paper-api/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java index e462ae9f9c72..015c553d41c8 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/components/EquippableComponent.java @@ -164,4 +164,32 @@ public interface EquippableComponent extends ConfigurationSerializable { * @param equip whether the item equips on interact */ void setEquipOnInteract(boolean equip); + + /** + * Checks if the item can be unequipped when interacting with an entity using shears. + * + * @return whether the item can be unequipped using shears + */ + boolean canBeSheared(); + + /** + * Sets if the item can be unequipped when interacting with an entity using shears. + * + * @param sheared whether the item can be unequipped using shears + */ + void setCanBeSheared(boolean sheared); + + /** + * Gets the sound to play when the item is sheared. + * + * @return the sound + */ + @Nullable Sound getShearingSound(); + + /** + * Sets the sound to play when the item is sheared. + * + * @param sound sound or null for current default + */ + void setShearingSound(@Nullable Sound sound); } diff --git a/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java index 6fe82caf86fc..35b36ba09010 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +++ b/paper-api/src/main/java/org/bukkit/plugin/java/LibraryLoader.java @@ -46,8 +46,7 @@ public class LibraryLoader { private final RepositorySystem repository; private final DefaultRepositorySystemSession session; private final List repositories; - public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries - public static java.util.function.Function, List> REMAPPER; // Paper - remap libraries + public static java.util.function.BiFunction LIBRARY_LOADER_FACTORY; // Paper - bytecode rewriting hook private static List getRepositories() { return List.of(new RemoteRepository.Builder("central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build()); @@ -131,9 +130,6 @@ public ClassLoader createLoader(@NotNull PluginDescriptionFile desc, java.util.@ jarPaths.add(artifact.getArtifact().getFile().toPath()); } } - if (REMAPPER != null) { - jarPaths = REMAPPER.apply(jarPaths); - } for (java.nio.file.Path path : jarPaths) { File file = path.toFile(); // Paper end - remap libraries @@ -152,14 +148,14 @@ public ClassLoader createLoader(@NotNull PluginDescriptionFile desc, java.util.@ }); } - // Paper start - rewrite reflection in libraries + // Paper start - bytecode rewriting hook URLClassLoader loader; if (LIBRARY_LOADER_FACTORY == null) { loader = new URLClassLoader(jarFiles.toArray(new URL[jarFiles.size()]), getClass().getClassLoader()); } else { loader = LIBRARY_LOADER_FACTORY.apply(jarFiles.toArray(new URL[jarFiles.size()]), getClass().getClassLoader()); } - // Paper end - rewrite reflection in libraries + // Paper end - bytecode rewriting hook return loader; } diff --git a/paper-api/src/main/java/org/bukkit/util/NumberConversions.java b/paper-api/src/main/java/org/bukkit/util/NumberConversions.java index e10b9a4e5343..07464b85895d 100644 --- a/paper-api/src/main/java/org/bukkit/util/NumberConversions.java +++ b/paper-api/src/main/java/org/bukkit/util/NumberConversions.java @@ -20,7 +20,7 @@ public static int ceil(final double num) { } public static int round(double num) { - return floor(num + 0.5d); + return floor(num + 0.5); } public static double square(double num) { diff --git a/paper-api/src/main/java/org/bukkit/util/Vector.java b/paper-api/src/main/java/org/bukkit/util/Vector.java index 4607b15f3c58..acae8a9f35f5 100644 --- a/paper-api/src/main/java/org/bukkit/util/Vector.java +++ b/paper-api/src/main/java/org/bukkit/util/Vector.java @@ -388,9 +388,9 @@ public boolean isZero() { */ @NotNull Vector normalizeZeros() { - if (x == -0.0D) x = 0.0D; - if (y == -0.0D) y = 0.0D; - if (z == -0.0D) z = 0.0D; + if (x == -0.0) x = 0.0; + if (y == -0.0) y = 0.0; + if (z == -0.0) z = 0.0; return this; } diff --git a/paper-api/src/test/java/org/bukkit/metadata/FixedMetadataValueTest.java b/paper-api/src/test/java/org/bukkit/metadata/FixedMetadataValueTest.java index 5dd537cf4dc0..2cc2bf3e87ca 100644 --- a/paper-api/src/test/java/org/bukkit/metadata/FixedMetadataValueTest.java +++ b/paper-api/src/test/java/org/bukkit/metadata/FixedMetadataValueTest.java @@ -24,7 +24,7 @@ public void testNumberTypes() { assertTrue(subject.asBoolean()); assertEquals(5, subject.asByte()); assertEquals(5.0, subject.asFloat(), 0.1e-8); - assertEquals(5.0D, subject.asDouble(), 0.1e-8D); + assertEquals(5.0, subject.asDouble(), 0.1e-8); assertEquals(5L, subject.asLong()); assertEquals(5, subject.asShort()); assertEquals("5", subject.asString()); diff --git a/paper-api/src/test/java/org/bukkit/util/BoundingBoxTest.java b/paper-api/src/test/java/org/bukkit/util/BoundingBoxTest.java index 3141c007d115..ea3754b0d74a 100644 --- a/paper-api/src/test/java/org/bukkit/util/BoundingBoxTest.java +++ b/paper-api/src/test/java/org/bukkit/util/BoundingBoxTest.java @@ -16,33 +16,33 @@ public void testConstruction() { BoundingBox expected = new BoundingBox(-1, -1, -1, 1, 2, 3); assertThat(expected.getMin(), is(new Vector(-1, -1, -1))); assertThat(expected.getMax(), is(new Vector(1, 2, 3))); - assertThat(expected.getCenter(), is(new Vector(0.0D, 0.5D, 1.0D))); - assertThat(expected.getWidthX(), is(2.0D)); - assertThat(expected.getHeight(), is(3.0D)); - assertThat(expected.getWidthZ(), is(4.0D)); - assertThat(expected.getVolume(), is(24.0D)); + assertThat(expected.getCenter(), is(new Vector(0.0, 0.5, 1.0))); + assertThat(expected.getWidthX(), is(2.0)); + assertThat(expected.getHeight(), is(3.0)); + assertThat(expected.getWidthZ(), is(4.0)); + assertThat(expected.getVolume(), is(24.0)); assertThat(BoundingBox.of(new Vector(-1, -1, -1), new Vector(1, 2, 3)), is(expected)); assertThat(BoundingBox.of(new Vector(1, 2, 3), new Vector(-1, -1, -1)), is(expected)); assertThat(BoundingBox.of(new Location(null, -1, -1, -1), new Location(null, 1, 2, 3)), is(expected)); - assertThat(BoundingBox.of(new Vector(0.0D, 0.5D, 1.0D), 1.0D, 1.5D, 2.0D), is(expected)); - assertThat(BoundingBox.of(new Location(null, 0.0D, 0.5D, 1.0D), 1.0D, 1.5D, 2.0D), is(expected)); + assertThat(BoundingBox.of(new Vector(0.0, 0.5, 1.0), 1.0, 1.5, 2.0), is(expected)); + assertThat(BoundingBox.of(new Location(null, 0.0, 0.5, 1.0), 1.0, 1.5, 2.0), is(expected)); } @Test public void testContains() { BoundingBox aabb = new BoundingBox(-1, -1, -1, 1, 2, 3); - assertThat(aabb.contains(-0.5D, 0.0D, 0.5D), is(true)); - assertThat(aabb.contains(-1.0D, -1.0D, -1.0D), is(true)); - assertThat(aabb.contains(1.0D, 2.0D, 3.0D), is(false)); - assertThat(aabb.contains(-1.0D, 1.0D, 4.0D), is(false)); - assertThat(aabb.contains(new Vector(-0.5D, 0.0D, 0.5D)), is(true)); + assertThat(aabb.contains(-0.5, 0.0, 0.5), is(true)); + assertThat(aabb.contains(-1.0, -1.0, -1.0), is(true)); + assertThat(aabb.contains(1.0, 2.0, 3.0), is(false)); + assertThat(aabb.contains(-1.0, 1.0, 4.0), is(false)); + assertThat(aabb.contains(new Vector(-0.5, 0.0, 0.5)), is(true)); - assertThat(aabb.contains(new BoundingBox(-0.5D, -0.5D, -0.5D, 0.5D, 1.0D, 2.0D)), is(true)); + assertThat(aabb.contains(new BoundingBox(-0.5, -0.5, -0.5, 0.5, 1.0, 2.0)), is(true)); assertThat(aabb.contains(aabb), is(true)); assertThat(aabb.contains(new BoundingBox(-1, -1, -1, 1, 1, 3)), is(true)); assertThat(aabb.contains(new BoundingBox(-2, -1, -1, 1, 2, 3)), is(false)); - assertThat(aabb.contains(new Vector(-0.5D, -0.5D, -0.5D), new Vector(0.5D, 1.0D, 2.0D)), is(true)); + assertThat(aabb.contains(new Vector(-0.5, -0.5, -0.5), new Vector(0.5, 1.0, 2.0)), is(true)); } @Test @@ -50,20 +50,20 @@ public void testOverlaps() { BoundingBox aabb = new BoundingBox(-1, -1, -1, 1, 2, 3); assertThat(aabb.contains(aabb), is(true)); assertThat(aabb.overlaps(new BoundingBox(-2, -2, -2, 0, 0, 0)), is(true)); - assertThat(aabb.overlaps(new BoundingBox(0.5D, 1.5D, 2.5D, 1, 2, 3)), is(true)); - assertThat(aabb.overlaps(new BoundingBox(0.5D, 1.5D, 2.5D, 2, 3, 4)), is(true)); + assertThat(aabb.overlaps(new BoundingBox(0.5, 1.5, 2.5, 1, 2, 3)), is(true)); + assertThat(aabb.overlaps(new BoundingBox(0.5, 1.5, 2.5, 2, 3, 4)), is(true)); assertThat(aabb.overlaps(new BoundingBox(-2, -2, -2, -1, -1, -1)), is(false)); assertThat(aabb.overlaps(new BoundingBox(1, 2, 3, 2, 3, 4)), is(false)); - assertThat(aabb.overlaps(new Vector(0.5D, 1.5D, 2.5D), new Vector(1, 2, 3)), is(true)); + assertThat(aabb.overlaps(new Vector(0.5, 1.5, 2.5), new Vector(1, 2, 3)), is(true)); } @Test public void testDegenerate() { BoundingBox aabb = new BoundingBox(0, 0, 0, 0, 0, 0); - assertThat(aabb.getWidthX(), is(0.0D)); - assertThat(aabb.getHeight(), is(0.0D)); - assertThat(aabb.getWidthZ(), is(0.0D)); - assertThat(aabb.getVolume(), is(0.0D)); + assertThat(aabb.getWidthX(), is(0.0)); + assertThat(aabb.getHeight(), is(0.0)); + assertThat(aabb.getWidthZ(), is(0.0)); + assertThat(aabb.getVolume(), is(0.0)); } @Test @@ -100,35 +100,35 @@ public void testExpansion() { assertThat(aabb.clone().expand(-1, -2, -3, -0.5D, -0.5, -3), is(new BoundingBox(1, 1.5D, 1, 1.5D, 1.5D, 1))); assertThat(aabb.clone().expand(1, 2, 3), is(new BoundingBox(-1, -2, -3, 3, 4, 5))); - assertThat(aabb.clone().expand(-0.1, -0.5, -2), is(new BoundingBox(0.1D, 0.5D, 1, 1.9D, 1.5D, 1))); + assertThat(aabb.clone().expand(-0.1, -0.5, -2), is(new BoundingBox(0.1, 0.5, 1, 1.9, 1.5, 1))); assertThat(aabb.clone().expand(new Vector(1, 2, 3)), is(new BoundingBox(-1, -2, -3, 3, 4, 5))); assertThat(aabb.clone().expand(1), is(new BoundingBox(-1, -1, -1, 3, 3, 3))); - assertThat(aabb.clone().expand(-0.5D), is(new BoundingBox(0.5D, 0.5D, 0.5D, 1.5D, 1.5D, 1.5D))); - - assertThat(aabb.clone().expand(1, 0, 0, 0.5D), is(new BoundingBox(0, 0, 0, 2.5D, 2, 2))); - assertThat(aabb.clone().expand(1, 0, 0, -0.5D), is(new BoundingBox(0, 0, 0, 1.5D, 2, 2))); - assertThat(aabb.clone().expand(-1, 0, 0, 0.5D), is(new BoundingBox(-0.5D, 0, 0, 2, 2, 2))); - assertThat(aabb.clone().expand(-1, 0, 0, -0.5D), is(new BoundingBox(0.5D, 0, 0, 2, 2, 2))); - - assertThat(aabb.clone().expand(0, 1, 0, 0.5D), is(new BoundingBox(0, 0, 0, 2, 2.5D, 2))); - assertThat(aabb.clone().expand(0, 1, 0, -0.5D), is(new BoundingBox(0, 0, 0, 2, 1.5D, 2))); - assertThat(aabb.clone().expand(0, -1, 0, 0.5D), is(new BoundingBox(0, -0.5D, 0, 2, 2, 2))); - assertThat(aabb.clone().expand(0, -1, 0, -0.5D), is(new BoundingBox(0, 0.5D, 0, 2, 2, 2))); - - assertThat(aabb.clone().expand(0, 0, 1, 0.5D), is(new BoundingBox(0, 0, 0, 2, 2, 2.5D))); - assertThat(aabb.clone().expand(0, 0, 1, -0.5D), is(new BoundingBox(0, 0, 0, 2, 2, 1.5D))); - assertThat(aabb.clone().expand(0, 0, -1, 0.5D), is(new BoundingBox(0, 0, -0.5D, 2, 2, 2))); - assertThat(aabb.clone().expand(0, 0, -1, -0.5D), is(new BoundingBox(0, 0, 0.5D, 2, 2, 2))); - - assertThat(aabb.clone().expand(new Vector(1, 0, 0), 0.5D), is(new BoundingBox(0, 0, 0, 2.5D, 2, 2))); - assertThat(aabb.clone().expand(BlockFace.EAST, 0.5D), is(new BoundingBox(0, 0, 0, 2.5D, 2, 2))); - assertThat(aabb.clone().expand(BlockFace.NORTH_NORTH_WEST, 1.0D), is(aabb.clone().expand(BlockFace.NORTH_NORTH_WEST.getDirection(), 1.0D))); - assertThat(aabb.clone().expand(BlockFace.SELF, 1.0D), is(aabb)); - - BoundingBox expanded = aabb.clone().expand(BlockFace.NORTH_WEST, 1.0D); - assertThat(expanded.getWidthX(), is(closeTo(aabb.getWidthX() + Math.sqrt(0.5D), delta))); - assertThat(expanded.getWidthZ(), is(closeTo(aabb.getWidthZ() + Math.sqrt(0.5D), delta))); + assertThat(aabb.clone().expand(-0.5D), is(new BoundingBox(0.5, 0.5, 0.5, 1.5, 1.5, 1.5))); + + assertThat(aabb.clone().expand(1, 0, 0, 0.5), is(new BoundingBox(0, 0, 0, 2.5, 2, 2))); + assertThat(aabb.clone().expand(1, 0, 0, -0.5), is(new BoundingBox(0, 0, 0, 1.5, 2, 2))); + assertThat(aabb.clone().expand(-1, 0, 0, 0.5), is(new BoundingBox(-0.5, 0, 0, 2, 2, 2))); + assertThat(aabb.clone().expand(-1, 0, 0, -0.5), is(new BoundingBox(0.5, 0, 0, 2, 2, 2))); + + assertThat(aabb.clone().expand(0, 1, 0, 0.5), is(new BoundingBox(0, 0, 0, 2, 2.5, 2))); + assertThat(aabb.clone().expand(0, 1, 0, -0.5), is(new BoundingBox(0, 0, 0, 2, 1.5, 2))); + assertThat(aabb.clone().expand(0, -1, 0, 0.5), is(new BoundingBox(0, -0.5, 0, 2, 2, 2))); + assertThat(aabb.clone().expand(0, -1, 0, -0.5), is(new BoundingBox(0, 0.5, 0, 2, 2, 2))); + + assertThat(aabb.clone().expand(0, 0, 1, 0.5), is(new BoundingBox(0, 0, 0, 2, 2, 2.5))); + assertThat(aabb.clone().expand(0, 0, 1, -0.5), is(new BoundingBox(0, 0, 0, 2, 2, 1.5))); + assertThat(aabb.clone().expand(0, 0, -1, 0.5), is(new BoundingBox(0, 0, -0.5, 2, 2, 2))); + assertThat(aabb.clone().expand(0, 0, -1, -0.5), is(new BoundingBox(0, 0, 0.5, 2, 2, 2))); + + assertThat(aabb.clone().expand(new Vector(1, 0, 0), 0.5), is(new BoundingBox(0, 0, 0, 2.5, 2, 2))); + assertThat(aabb.clone().expand(BlockFace.EAST, 0.5), is(new BoundingBox(0, 0, 0, 2.5, 2, 2))); + assertThat(aabb.clone().expand(BlockFace.NORTH_NORTH_WEST, 1.0), is(aabb.clone().expand(BlockFace.NORTH_NORTH_WEST.getDirection(), 1.0))); + assertThat(aabb.clone().expand(BlockFace.SELF, 1.0), is(aabb)); + + BoundingBox expanded = aabb.clone().expand(BlockFace.NORTH_WEST, 1.0); + assertThat(expanded.getWidthX(), is(closeTo(aabb.getWidthX() + Math.sqrt(0.5), delta))); + assertThat(expanded.getWidthZ(), is(closeTo(aabb.getWidthZ() + Math.sqrt(0.5), delta))); assertThat(expanded.getHeight(), is(aabb.getHeight())); assertThat(aabb.clone().expandDirectional(1, 2, 3), is(new BoundingBox(0, 0, 0, 3, 4, 5))); @@ -176,7 +176,7 @@ public void testRayTrace() { assertThat(aabb.rayTrace(new Vector(0, 0, -3), new Vector(1, 0, 1), 10), is(nullValue())); assertThat(aabb.rayTrace(new Vector(0, 0, -2), new Vector(1, 0, 2), 10), - is(new RayTraceResult(new Vector(0.5D, 0, -1), BlockFace.NORTH))); + is(new RayTraceResult(new Vector(0.5, 0, -1), BlockFace.NORTH))); // corner/edge hits yield unspecified block face: assertThat(aabb.rayTrace(new Vector(2, 2, 2), new Vector(-1, -1, -1), 10), diff --git a/paper-generator/build.gradle.kts b/paper-generator/build.gradle.kts index d305a18dc35e..887de4322c85 100644 --- a/paper-generator/build.gradle.kts +++ b/paper-generator/build.gradle.kts @@ -24,10 +24,10 @@ dependencies { isTransitive = false // paper-api already have everything } implementation("info.picocli:picocli:4.7.7") - implementation("io.github.classgraph:classgraph:4.8.179") + implementation("io.github.classgraph:classgraph:4.8.184") implementation("org.jetbrains:annotations:26.0.2") - testImplementation("org.junit.jupiter:junit-jupiter:5.12.2") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testImplementation("org.junit.jupiter:junit-jupiter:6.0.3") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.0.3") serverRuntimeClasspath(project(":paper-server", "runtimeConfiguration")) } diff --git a/paper-generator/src/main/java/io/papermc/generator/Main.java b/paper-generator/src/main/java/io/papermc/generator/Main.java index 3a1ab1537111..41dd028d2d0e 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Main.java +++ b/paper-generator/src/main/java/io/papermc/generator/Main.java @@ -85,10 +85,10 @@ public static CompletableFuture bootStrap(boolean withTags) { LayeredRegistryAccess layers = RegistryLayer.createRegistryAccess(); List> pendingTags = TagLoader.loadTagsForExistingRegistries(resourceManager, layers.getLayer(RegistryLayer.STATIC)); List> worldGenLayer = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLDGEN), pendingTags); - RegistryAccess.Frozen frozenWorldgenRegistries = RegistryDataLoader.load(resourceManager, worldGenLayer, RegistryDataLoader.WORLDGEN_REGISTRIES); + RegistryAccess.Frozen frozenWorldgenRegistries = RegistryDataLoader.load(resourceManager, worldGenLayer, RegistryDataLoader.WORLDGEN_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.WORLDGEN, frozenWorldgenRegistries); List> staticAndWorldgenLookups = Stream.concat(worldGenLayer.stream(), frozenWorldgenRegistries.listRegistries()).toList(); - RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES); + RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensionRegistries); REGISTRY_ACCESS = layers.compositeAccess().freeze(); if (withTags) { @@ -106,7 +106,7 @@ public static CompletableFuture bootStrap(boolean withTags) { resourceManager.close(); } }).thenAccept(resources -> { - resources.updateStaticRegistryTags(); + resources.updateComponentsAndStaticRegistryTags(); EXPERIMENTAL_TAGS = ExperimentalCollector.collectTags(resourceManager); }); } else { diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index dee77d43ba9a..c880dad1aee2 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -26,6 +26,7 @@ import io.papermc.paper.datacomponent.item.SwingAnimation; import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.item.MapPostProcessing; import io.papermc.paper.world.WeatheringCopperState; import io.papermc.typewriter.preset.EnumCloneRewriter; import io.papermc.typewriter.preset.model.EnumValue; @@ -160,6 +161,7 @@ protected EnumValue.Builder rewriteEnumValue(ParticleStatus status) { )) .register("ItemUseAnimation", ItemUseAnimation.class, new EnumCloneRewriter<>(net.minecraft.world.item.ItemUseAnimation.class)) .register("SwingAnimationType", SwingAnimation.Animation.class, new EnumCloneRewriter<>(SwingAnimationType.class)) + .register("MapPostProcessing", MapPostProcessing.class, new EnumCloneRewriter<>(net.minecraft.world.item.component.MapPostProcessing.class)) .register("ItemRarity", ItemRarity.class, new EnumCloneRewriter<>(Rarity.class) { @Override protected EnumValue.Builder rewriteEnumValue(Rarity rarity) { @@ -213,6 +215,7 @@ protected String rewriteFieldType(Holder.Reference(Registries.WOLF_VARIANT, "getVariant")) .register("WolfSoundVariant", Wolf.SoundVariant.class, new RegistryFieldRewriter<>(Registries.WOLF_SOUND_VARIANT, "getSoundVariant")) .register("CatType", Cat.Type.class, new RegistryFieldRewriter<>(Registries.CAT_VARIANT, "getType")) + .register("CatSoundVariant", Cat.SoundVariant.class, new RegistryFieldRewriter<>(Registries.CAT_SOUND_VARIANT, "getSoundVariant")) .register("FrogVariant", Frog.Variant.class, new RegistryFieldRewriter<>(Registries.FROG_VARIANT, "getVariant")) .register("PatternType", PatternType.class, new RegistryFieldRewriter<>(Registries.BANNER_PATTERN, "getType")) .register("Biome", Biome.class, new RegistryFieldRewriter<>(Registries.BIOME, "getBiome")) @@ -221,8 +224,11 @@ protected String rewriteFieldType(Holder.Reference(Registries.SOUND_EVENT, "getSound")) .register("Art", Art.class, new RegistryFieldRewriter<>(Registries.PAINTING_VARIANT, "getArt")) .register("ChickenVariant", Chicken.Variant.class, new RegistryFieldRewriter<>(Registries.CHICKEN_VARIANT, "getVariant")) + .register("ChickenSoundVariant", Chicken.SoundVariant.class, new RegistryFieldRewriter<>(Registries.CHICKEN_SOUND_VARIANT, "getSoundVariant")) .register("CowVariant", Cow.Variant.class, new RegistryFieldRewriter<>(Registries.COW_VARIANT, "getVariant")) + .register("CowSoundVariant", Cow.SoundVariant.class, new RegistryFieldRewriter<>(Registries.COW_SOUND_VARIANT, "getSoundVariant")) .register("PigVariant", Pig.Variant.class, new RegistryFieldRewriter<>(Registries.PIG_VARIANT, "getVariant")) + .register("PigSoundVariant", Pig.SoundVariant.class, new RegistryFieldRewriter<>(Registries.PIG_SOUND_VARIANT, "getSoundVariant")) .register("ZombieNautilusVariant", ZombieNautilus.Variant.class, new RegistryFieldRewriter<>(Registries.ZOMBIE_NAUTILUS_VARIANT, "getVariant")) .register("Dialog", Dialog.class, new RegistryFieldRewriter<>(Registries.DIALOG, "getDialog")) .register("MemoryKey", MemoryKey.class, new MemoryKeyRewriter()) @@ -236,7 +242,7 @@ protected String rewriteFieldType(Holder.Reference generators) { } }); - // todo remove once entity type is a registry + // todo remove once entity type and potion are both a registry generators.add(new GeneratedTagKeyType(RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE), PAPER_REGISTRY_PACKAGE + ".keys.tags")); + generators.add(new GeneratedTagKeyType(RegistryEntries.byRegistryKey(Registries.POTION), PAPER_REGISTRY_PACKAGE + ".keys.tags")); } public static void bootstrap(PatternSourceSetRewriter apiSourceSet, PatternSourceSetRewriter serverSourceSet) { diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 0a9f1e9a68f7..fe34adadee56 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -43,12 +43,16 @@ import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.animal.feline.CatVariants; +import net.minecraft.world.entity.animal.chicken.ChickenSoundVariants; import net.minecraft.world.entity.animal.chicken.ChickenVariants; +import net.minecraft.world.entity.animal.cow.CowSoundVariants; import net.minecraft.world.entity.animal.cow.CowVariants; -import net.minecraft.world.entity.animal.pig.PigVariants; -import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariants; +import net.minecraft.world.entity.animal.feline.CatSoundVariants; +import net.minecraft.world.entity.animal.feline.CatVariants; import net.minecraft.world.entity.animal.frog.FrogVariants; +import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariants; +import net.minecraft.world.entity.animal.pig.PigSoundVariants; +import net.minecraft.world.entity.animal.pig.PigVariants; import net.minecraft.world.entity.animal.wolf.WolfSoundVariants; import net.minecraft.world.entity.animal.wolf.WolfVariants; import net.minecraft.world.entity.decoration.painting.PaintingVariants; @@ -153,7 +157,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> REGISTRY_CLASS_NAME_BASED_ON_API = Set.of( BlockType.class, - ItemType.class + ItemType.class, + PotionType.class ); public static final List> BUILT_IN = List.of( @@ -187,10 +192,14 @@ private static RegistryEntry inconsistentEntry(ResourceKey> reference) { .orElseThrow(() -> new IllegalStateException("Could not find entity class for " + reference.key().identifier())) .resolve(runtime); Preconditions.checkArgument(org.bukkit.entity.Entity.class.isAssignableFrom(resolvedClass.knownClass()), "Generic type must be an entity"); - return this.importCollector.getShortName(this.classNamedView.findFirst(CLASS_RENAMES.getOrDefault(className, className)).resolve(runtime)); + return this.importCollector.getShortName(resolvedClass); } } diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/BlockStateMapping.java b/paper-generator/src/main/java/io/papermc/generator/utils/BlockStateMapping.java index b8787b0939ac..65f77112b593 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/BlockStateMapping.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/BlockStateMapping.java @@ -130,7 +130,6 @@ public record BlockData(String implName, @Nullable Class "$project-$version-$build.jar" } } } diff --git a/paper-server/patches/features/0003-Optimize-Network-Manager-and-add-advanced-packet-sup.patch b/paper-server/patches/features/0001-Optimize-Connection-and-add-advanced-packet-support.patch similarity index 83% rename from paper-server/patches/features/0003-Optimize-Network-Manager-and-add-advanced-packet-sup.patch rename to paper-server/patches/features/0001-Optimize-Connection-and-add-advanced-packet-support.patch index bd8a743b0fdf..592e7730b449 100644 --- a/paper-server/patches/features/0003-Optimize-Network-Manager-and-add-advanced-packet-sup.patch +++ b/paper-server/patches/features/0001-Optimize-Connection-and-add-advanced-packet-support.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Wed, 6 May 2020 04:53:35 -0400 -Subject: [PATCH] Optimize Network Manager and add advanced packet support +Subject: [PATCH] Optimize Connection and add advanced packet support Adds ability for 1 packet to bundle other packets to follow it Adds ability for a packet to delay sending more packets until a state is ready. @@ -28,7 +28,7 @@ and then catch exceptions and close if they fire. Part of this commit was authored by: Spottedleaf, sandtechnology diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364ccfa390e5 100644 +index 6fb9eb8078e934d3d610ec58f58e0a47bc3437b8..d65a8f0cc7386270471338454d35c52bdbcd8e82 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java @@ -65,7 +65,7 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -49,12 +49,12 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + public boolean queueImmunity; + // Paper end - Optimize network - public Connection(PacketFlow receiving) { + public Connection(final PacketFlow receiving) { this.receiving = receiving; -@@ -395,11 +399,38 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -393,11 +397,38 @@ public class Connection extends SimpleChannelInboundHandler> { } - public void send(Packet packet, @Nullable ChannelFutureListener sendListener, boolean flush) { + public void send(final Packet packet, final @Nullable ChannelFutureListener listener, final boolean flush) { - if (this.isConnected()) { - this.flushQueue(); + // Paper start - Optimize network: Handle oversized packets better @@ -67,14 +67,14 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + if (connected && (InnerUtil.canSendImmediate(this, packet) + || (io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.pendingActions.isEmpty() + && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty())))) { - this.sendPacket(packet, sendListener, flush); + this.sendPacket(packet, listener, flush); } else { -- this.pendingActions.add(connection -> connection.sendPacket(packet, sendListener, flush)); +- this.pendingActions.add(connection -> connection.sendPacket(packet, listener, flush)); + // Write the packets to the queue, then flush - antixray hooks there already + final java.util.List> extraPackets = InnerUtil.buildExtraPackets(packet); + final boolean hasExtraPackets = extraPackets != null && !extraPackets.isEmpty(); + if (!hasExtraPackets) { -+ this.pendingActions.add(new PacketSendAction(packet, sendListener, flush)); ++ this.pendingActions.add(new PacketSendAction(packet, listener, flush)); + } else { + final java.util.List actions = new java.util.ArrayList<>(1 + extraPackets.size()); + actions.add(new PacketSendAction(packet, null, false)); // Delay the future listener until the end of the extra packets @@ -82,7 +82,7 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + for (int i = 0, len = extraPackets.size(); i < len;) { + final Packet extraPacket = extraPackets.get(i); + final boolean end = ++i == len; -+ actions.add(new PacketSendAction(extraPacket, end ? sendListener : null, end)); // Append listener to the end ++ actions.add(new PacketSendAction(extraPacket, end ? listener : null, end)); // Append listener to the end + } + + this.pendingActions.addAll(actions); @@ -93,7 +93,7 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c } } -@@ -408,7 +439,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -406,7 +437,7 @@ public class Connection extends SimpleChannelInboundHandler> { this.flushQueue(); action.accept(this); } else { @@ -102,10 +102,10 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c } } -@@ -422,21 +453,41 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -420,21 +451,41 @@ public class Connection extends SimpleChannelInboundHandler> { } - private void doSendPacket(Packet packet, @Nullable ChannelFutureListener sendListener, boolean flush) { + private void doSendPacket(final Packet packet, final @Nullable ChannelFutureListener listener, final boolean flush) { + // Paper start - Optimize network + final net.minecraft.server.level.ServerPlayer player = this.getPlayer(); + if (!this.isConnected()) { @@ -113,23 +113,23 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + return; + } + try { -+ final ChannelFuture channelFuture; ++ final ChannelFuture future; + // Paper end - Optimize network - if (sendListener != null) { -- ChannelFuture channelFuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); -+ channelFuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Paper - Optimize network - channelFuture.addListener(sendListener); + if (listener != null) { +- ChannelFuture future = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); ++ future = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Paper - Optimize network + future.addListener(listener); } else if (flush) { - this.channel.writeAndFlush(packet, this.channel.voidPromise()); -+ channelFuture = this.channel.writeAndFlush(packet, this.channel.voidPromise()); // Paper - Optimize network ++ future = this.channel.writeAndFlush(packet, this.channel.voidPromise()); // Paper - Optimize network } else { - this.channel.write(packet, this.channel.voidPromise()); -+ channelFuture = this.channel.write(packet, this.channel.voidPromise()); // Paper - Optimize network ++ future = this.channel.write(packet, this.channel.voidPromise()); // Paper - Optimize network + } + + // Paper start - Optimize network + if (packet.hasFinishListener()) { -+ channelFuture.addListener((ChannelFutureListener) future -> packet.onPacketDispatchFinish(player, future)); ++ future.addListener((ChannelFutureListener) f -> packet.onPacketDispatchFinish(player, f)); + } + } catch (final Exception e) { + LOGGER.error("NetworkException: {}", player, e); @@ -148,7 +148,7 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c } } -@@ -448,16 +499,57 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -446,16 +497,57 @@ public class Connection extends SimpleChannelInboundHandler> { } } @@ -164,9 +164,9 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + } else if (this.isPending) { + // Should only happen during login/status stages synchronized (this.pendingActions) { -- Consumer consumer; -- while ((consumer = this.pendingActions.poll()) != null) { -- consumer.accept(this); +- Consumer pendingAction; +- while ((pendingAction = this.pendingActions.poll()) != null) { +- pendingAction.accept(this); + return this.processQueue(); + } + } @@ -211,15 +211,15 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world private static int joinAttemptsThisTick; // Paper - Buffer joins to world -@@ -527,6 +619,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -525,6 +617,7 @@ public class Connection extends SimpleChannelInboundHandler> { - public void disconnect(DisconnectionDetails disconnectionDetails) { + public void disconnect(final DisconnectionDetails details) { this.preparing = false; // Spigot + this.clearPacketQueue(); // Paper - Optimize network if (this.channel == null) { - this.delayedDisconnect = disconnectionDetails; + this.delayedDisconnect = details; } -@@ -703,7 +796,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -713,7 +806,7 @@ public class Connection extends SimpleChannelInboundHandler> { public void handleDisconnection() { if (this.channel != null && !this.channel.isOpen()) { if (this.disconnectionHandled) { @@ -228,17 +228,17 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c } else { this.disconnectionHandled = true; PacketListener packetListener = this.getPacketListener(); -@@ -714,7 +807,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -724,7 +817,7 @@ public class Connection extends SimpleChannelInboundHandler> { ); - packetListener1.onDisconnect(disconnectionDetails); + disconnectListener.onDisconnect(details); } - this.pendingActions.clear(); // Free up packet queue. + this.clearPacketQueue(); // Paper - Optimize network // Paper start - Add PlayerConnectionCloseEvent if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { /* Player was logged in, either game listener or configuration listener */ -@@ -749,4 +842,96 @@ public class Connection extends SimpleChannelInboundHandler> { - public void setBandwidthLogger(LocalSampleLogger bandwidthLogger) { +@@ -759,4 +852,96 @@ public class Connection extends SimpleChannelInboundHandler> { + public void setBandwidthLogger(final LocalSampleLogger bandwidthLogger) { this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwidthLogger); } + @@ -279,8 +279,8 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + } + } + -+ private static boolean canSendImmediate(final Connection networkManager, final net.minecraft.network.protocol.Packet packet) { -+ return networkManager.isPending || networkManager.packetListener.protocol() != ConnectionProtocol.PLAY || ++ private static boolean canSendImmediate(final Connection connection, final net.minecraft.network.protocol.Packet packet) { ++ return connection.isPending || connection.packetListener.protocol() != ConnectionProtocol.PLAY || + packet instanceof net.minecraft.network.protocol.common.ClientboundKeepAlivePacket || + packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket || + packet instanceof net.minecraft.network.protocol.game.ClientboundSystemChatPacket || @@ -335,12 +335,12 @@ index 68b081ef1b0bf9a58564d900569bc7a5dfef2a32..8817a2d6500d1bdce96d87dc8f7f364c + // Paper end - Optimize network } diff --git a/net/minecraft/network/protocol/Packet.java b/net/minecraft/network/protocol/Packet.java -index 65ff8b9112ec76eeac48c679044fc02ae7d4ffeb..062fd531edf6dfebb42dbaeee7bbda524316d3e4 100644 +index 1480d0db90f5797e3dee19503e52d1e783493ac3..f6cfce2ce30a426cd57a89f3f8ccf144b6050363 100644 --- a/net/minecraft/network/protocol/Packet.java +++ b/net/minecraft/network/protocol/Packet.java @@ -35,4 +35,32 @@ public interface Packet { - static > StreamCodec codec(StreamMemberEncoder encoder, StreamDecoder decoder) { - return StreamCodec.ofMember(encoder, decoder); + static > StreamCodec codec(final StreamMemberEncoder writer, final StreamDecoder reader) { + return StreamCodec.ofMember(writer, reader); } + + // Paper start @@ -372,10 +372,10 @@ index 65ff8b9112ec76eeac48c679044fc02ae7d4ffeb..062fd531edf6dfebb42dbaeee7bbda52 + // Paper end } diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java -index c080b4eccb94551eefd7016200431e37221232b5..309845b28306dfa5946e79b80e5b1dde82dd68cd 100644 +index e72bd8239eed69be774373b49cdb05fbf0799030..22276be80b8729884c797b96c93bf0965ca9eed1 100644 --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -50,11 +50,13 @@ public class ServerConnectionListener { +@@ -51,11 +51,13 @@ public class ServerConnectionListener { // Paper start - prevent blocking on adding a new connection while the server is ticking private final java.util.Queue pending = new java.util.concurrent.ConcurrentLinkedQueue<>(); @@ -389,11 +389,11 @@ index c080b4eccb94551eefd7016200431e37221232b5..309845b28306dfa5946e79b80e5b1dde } } // Paper end - prevent blocking on adding a new connection while the server is ticking -@@ -86,6 +88,7 @@ public class ServerConnectionListener { +@@ -91,6 +93,7 @@ public class ServerConnectionListener { } catch (ChannelException var5) { } + if (!disableFlushConsolidation) channel.pipeline().addFirst(new io.netty.handler.flush.FlushConsolidationHandler()); // Paper - Optimize network - ChannelPipeline channelPipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)); + ChannelPipeline pipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)); if (ServerConnectionListener.this.server.repliesToStatus()) { - channelPipeline.addLast("legacy_query", new LegacyQueryHandler(ServerConnectionListener.this.getServer())); + pipeline.addLast("legacy_query", new LegacyQueryHandler(ServerConnectionListener.this.getServer())); diff --git a/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch b/paper-server/patches/features/0002-Allow-Saving-of-Oversized-Chunks.patch similarity index 82% rename from paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch rename to paper-server/patches/features/0002-Allow-Saving-of-Oversized-Chunks.patch index 7cf5f74712b2..71acbb8f4903 100644 --- a/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch +++ b/paper-server/patches/features/0002-Allow-Saving-of-Oversized-Chunks.patch @@ -31,10 +31,10 @@ this fix, as the data will remain in the oversized file. Once the server returns to a jar with this fix, the data will be restored. diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 99bbae1f8f681950f410b2bfe9af037164d8dcb7..944a01c34d19225d8366f6f97cbc3cacbb5d5498 100644 +index 728ec122b7af090427cc7511a168336d539835a1..a60a417432cab517fd2fbfd4447c7cb7ecf40987 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -68,6 +68,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche +@@ -54,6 +54,7 @@ public class RegionFile implements AutoCloseable { this.info = info; this.path = path; this.version = version; @@ -42,8 +42,8 @@ index 99bbae1f8f681950f410b2bfe9af037164d8dcb7..944a01c34d19225d8366f6f97cbc3cac if (!Files.isDirectory(externalFileDir)) { throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath()); } else { -@@ -464,4 +465,75 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - interface CommitOp { +@@ -422,4 +423,75 @@ public class RegionFile implements AutoCloseable { + private interface CommitOp { void run() throws IOException; } + @@ -119,11 +119,11 @@ index 99bbae1f8f681950f410b2bfe9af037164d8dcb7..944a01c34d19225d8366f6f97cbc3cac + // Paper end } diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 5d9168242f7a7ca4dd888f32fecb27457fd89456..98b3f20c720d70293c6fcf77fdc081b44c71dd6b 100644 +index 7c6f16fa3de0d344202ec456c648aaebf24a69ca..6b265cc308a14846c9ef3c96aa5daf06e246b8a8 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -237,6 +237,43 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - // Paper end - rewrite chunk system +@@ -48,6 +48,43 @@ public final class RegionFileStorage implements AutoCloseable { + } } + // Paper start @@ -134,7 +134,7 @@ index 5d9168242f7a7ca4dd888f32fecb27457fd89456..98b3f20c720d70293c6fcf77fdc081b4 + private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { + synchronized (regionfile) { + try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { -+ CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); ++ CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x(), chunkCoordinate.z()); + CompoundTag chunk = NbtIo.read(datainputstream); + if (oversizedData == null) { + return chunk; @@ -163,27 +163,27 @@ index 5d9168242f7a7ca4dd888f32fecb27457fd89456..98b3f20c720d70293c6fcf77fdc081b4 + } + // Paper end + - public @Nullable CompoundTag read(ChunkPos chunkPos) throws IOException { + public @Nullable CompoundTag read(final ChunkPos pos) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing - RegionFile regionFile = this.getRegionFile(chunkPos, true); -@@ -244,6 +281,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + RegionFile region = this.getRegionFile(pos, true); +@@ -55,6 +92,12 @@ public final class RegionFileStorage implements AutoCloseable { return null; } // CraftBukkit end + // Paper start -+ if (regionFile.isOversized(chunkPos.x, chunkPos.z)) { -+ printOversizedLog("Loading Oversized Chunk!", regionFile.getPath(), chunkPos.x, chunkPos.z); -+ return readOversizedChunk(regionFile, chunkPos); ++ if (region.isOversized(pos.x(), pos.z())) { ++ printOversizedLog("Loading Oversized Chunk!", region.getPath(), pos.x(), pos.z()); ++ return readOversizedChunk(region, pos); + } + // Paper end CompoundTag var4; - try (DataInputStream chunkDataInputStream = regionFile.getChunkDataInputStream(chunkPos)) { -@@ -286,6 +329,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { +@@ -91,6 +134,7 @@ public final class RegionFileStorage implements AutoCloseable { } else { - try (DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos)) { - NbtIo.write(chunkData, chunkDataOutputStream); -+ regionFile.setOversized(chunkPos.x, chunkPos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone + try (DataOutputStream output = region.getChunkDataOutputStream(pos)) { + NbtIo.write(value, output); ++ region.setOversized(pos.x(), pos.z(), false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone } } } diff --git a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch b/paper-server/patches/features/0003-Entity-Activation-Range-2.0.patch similarity index 81% rename from paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch rename to paper-server/patches/features/0003-Entity-Activation-Range-2.0.patch index 6110e917e631..17538a281360 100644 --- a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch +++ b/paper-server/patches/features/0003-Entity-Activation-Range-2.0.patch @@ -354,81 +354,81 @@ index 0000000000000000000000000000000000000000..c18823746ab2edcab536cb1589b7720e + } +} diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 7656665352632fc718bea91dcfd3dd41fc436e1f..bdbc15bfbbfeae2bc5b884e300b86cb25c88840f 100644 +index 4f31c92c8c3b2757a4103a1b2a0ae158117eebd1..43c47bdd2fdb7731eec5301e20f923d0703a36fc 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -830,6 +830,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - profilerFiller.pop(); +@@ -591,6 +591,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet + profiler.pop(); } + io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR this.entityTickList .forEach( entity -> { -@@ -1347,12 +1348,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1064,12 +1065,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet entity.totalEntityAge++; // Paper - age-like counter for all entities - profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()); - profilerFiller.incrementCounter("tickNonPassenger"); + profiler.push(entity.typeHolder()::getRegisteredName); + profiler.incrementCounter("tickNonPassenger"); + final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 + if (isActive) { // Paper - EAR 2 entity.tick(); entity.postTick(); // CraftBukkit + } else {entity.inactiveTick();} // Paper - EAR 2 - profilerFiller.pop(); + profiler.pop(); - for (Entity entity1 : entity.getPassengers()) { -- this.tickPassenger(entity, entity1); -+ this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 + for (Entity passenger : entity.getPassengers()) { +- this.tickPassenger(entity, passenger); ++ this.tickPassenger(entity, passenger, isActive); // Paper - EAR 2 } // Paper start - log detailed entity tick information } finally { -@@ -1363,7 +1367,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1080,7 +1084,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet // Paper end - log detailed entity tick information } -- private void tickPassenger(Entity ridingEntity, Entity passengerEntity) { -+ private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 - if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) { - passengerEntity.stopRiding(); - } else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) { -@@ -1373,12 +1377,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString()); - profilerFiller.incrementCounter("tickPassenger"); +- private void tickPassenger(final Entity vehicle, final Entity entity) { ++ private void tickPassenger(final Entity vehicle, final Entity entity, final boolean isActive) { // Paper - EAR 2 + if (entity.isRemoved() || entity.getVehicle() != vehicle) { + entity.stopRiding(); + } else if (entity instanceof Player || this.entityTickList.contains(entity)) { +@@ -1090,12 +1094,21 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet + ProfilerFiller profiler = Profiler.get(); + profiler.push(entity.typeHolder()::getRegisteredName); + profiler.incrementCounter("tickPassenger"); + // Paper start - EAR 2 + if (isActive) { - passengerEntity.rideTick(); - passengerEntity.postTick(); // CraftBukkit + entity.rideTick(); + entity.postTick(); // CraftBukkit + } else { -+ passengerEntity.setDeltaMovement(Vec3.ZERO); -+ passengerEntity.inactiveTick(); ++ entity.setDeltaMovement(Vec3.ZERO); ++ entity.inactiveTick(); + // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary -+ ridingEntity.positionRider(passengerEntity); ++ vehicle.positionRider(entity); + } + // Paper end - EAR 2 - profilerFiller.pop(); + profiler.pop(); - for (Entity entity : passengerEntity.getPassengers()) { -- this.tickPassenger(passengerEntity, entity); -+ this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 + for (Entity passenger : entity.getPassengers()) { +- this.tickPassenger(entity, passenger); ++ this.tickPassenger(entity, passenger, isActive); // Paper - EAR 2 } } } diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java -index d4452e28a7c65c464c97d5553985c82e59672108..4b918f07a13e7b99c25f92ae377742cf0a7e2ead 100644 +index 4f98f6e1ca266ab7377fb52e753b977d4ccd1558..a0c930afcdb01e2fb103836613417fb9fc96d86b 100644 --- a/net/minecraft/world/entity/AgeableMob.java +++ b/net/minecraft/world/entity/AgeableMob.java -@@ -129,6 +129,21 @@ public abstract class AgeableMob extends PathfinderMob { - super.onSyncedDataUpdated(key); +@@ -184,6 +184,21 @@ public abstract class AgeableMob extends PathfinderMob { + super.onSyncedDataUpdated(accessor); } + // Paper start - EAR 2 + @Override + public void inactiveTick() { + super.inactiveTick(); -+ if (!this.ageLocked && this.isAlive()) { ++ if (this.isAlive()) { + int age = this.getAge(); -+ if (age < 0) { ++ if (this.canAgeUp()) { + this.setAge(++age); + } else if (age > 0) { + this.setAge(--age); @@ -441,7 +441,7 @@ index d4452e28a7c65c464c97d5553985c82e59672108..4b918f07a13e7b99c25f92ae377742cf public void aiStep() { super.aiStep(); diff --git a/net/minecraft/world/entity/AreaEffectCloud.java b/net/minecraft/world/entity/AreaEffectCloud.java -index 5461bd9a39bb20ad29d3bc110c38860cf35a770a..b10762fd050ca03c1d31dc57e42739a1f114ca2f 100644 +index 6309a615ba2525437758b1fe39c43060ec42d6f8..677b0cadec2270537d868aac7d0acaf7e6bfa2ea 100644 --- a/net/minecraft/world/entity/AreaEffectCloud.java +++ b/net/minecraft/world/entity/AreaEffectCloud.java @@ -140,6 +140,16 @@ public class AreaEffectCloud extends Entity implements TraceableEntity { @@ -462,10 +462,10 @@ index 5461bd9a39bb20ad29d3bc110c38860cf35a770a..b10762fd050ca03c1d31dc57e42739a1 public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 34ef15867759ebc7296256a6d5ec286eb3a5f895..d3d97b0b6ff6312f1deb0bb8b1beef8b3578bc53 100644 +index 931a886ab969009c1dc672e3108a0e65f888e0f4..83602c8ee3e2d6064fea66a915f427ffe1584b5a 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -368,6 +368,15 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -426,6 +426,15 @@ public abstract class Entity private final int despawnTime; // Paper - entity despawn time limit public int totalEntityAge; // Paper - age-like counter for all entities public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges @@ -481,7 +481,7 @@ index 34ef15867759ebc7296256a6d5ec286eb3a5f895..d3d97b0b6ff6312f1deb0bb8b1beef8b // CraftBukkit end // Paper start -@@ -533,6 +542,13 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -441,6 +450,13 @@ public abstract class Entity this.position = Vec3.ZERO; this.blockPosition = BlockPos.ZERO; this.chunkPosition = ChunkPos.ZERO; @@ -492,39 +492,39 @@ index 34ef15867759ebc7296256a6d5ec286eb3a5f895..d3d97b0b6ff6312f1deb0bb8b1beef8b + this.defaultActivationState = false; + } + // Paper end - EAR 2 - SynchedEntityData.Builder builder = new SynchedEntityData.Builder(this); - builder.define(DATA_SHARED_FLAGS_ID, (byte)0); - builder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply()); -@@ -1115,6 +1131,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name - this.minorHorizontalCollision = false; + SynchedEntityData.Builder entityDataBuilder = new SynchedEntityData.Builder(this); + entityDataBuilder.define(DATA_SHARED_FLAGS_ID, (byte)0); + entityDataBuilder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply()); +@@ -1029,6 +1045,10 @@ public abstract class Entity } else { - if (type == MoverType.PISTON) { + if (moverType == MoverType.PISTON) { + delta = this.limitPistonMovement(delta); + // Paper start - EAR 2 + this.activatedTick = Math.max(this.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 20); + this.activatedImmunityTick = Math.max(this.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 20); + // Paper end - EAR 2 - movement = this.limitPistonMovement(movement); - if (movement.equals(Vec3.ZERO)) { + if (delta.equals(Vec3.ZERO)) { return; -@@ -1131,6 +1151,13 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name + } +@@ -1044,6 +1064,13 @@ public abstract class Entity this.stuckSpeedMultiplier = Vec3.ZERO; this.setDeltaMovement(Vec3.ZERO); } + // Paper start - ignore movement changes while inactive. -+ if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) { ++ if (isTemporarilyActive && !(this instanceof ItemEntity) && delta == getDeltaMovement() && moverType == MoverType.SELF) { + setDeltaMovement(Vec3.ZERO); -+ profilerFiller.pop(); ++ profiler.pop(); + return; + } + // Paper end - movement = this.maybeBackOffFromEdge(movement, type); - Vec3 vec3 = this.collide(movement); + delta = this.maybeBackOffFromEdge(delta, moverType); + Vec3 movement = this.collide(delta); diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 5b6020de0848458f5576113e690b5a6435f35d05..6f49b5e5888a6296b929e465a5ef87dc49bd4516 100644 +index e0e6c0f1ab9609fb64db4dfd436414d7ce12dd12..cbcef6d9d4113e318237df4501839d6870042c8d 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -3330,6 +3330,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3385,6 +3385,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin protected void playAttackSound() { } @@ -540,10 +540,10 @@ index 5b6020de0848458f5576113e690b5a6435f35d05..6f49b5e5888a6296b929e465a5ef87dc public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java -index 95c99f266f259042d5946e891f9bab04d2fdba2a..92175cc019750e829fcad7691a937024c2649882 100644 +index dab431458aa93349a9f09e8e3502a8b8b11a1653..2c7efcc76da5c2d1596bd15128fa27d77acc152d 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java -@@ -217,6 +217,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab +@@ -211,6 +211,19 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs return this.lookControl; } @@ -561,10 +561,10 @@ index 95c99f266f259042d5946e891f9bab04d2fdba2a..92175cc019750e829fcad7691a937024 + // Paper end + public MoveControl getMoveControl() { - return this.getControlledVehicle() instanceof Mob mob ? mob.getMoveControl() : this.moveControl; + return this.getControlledVehicle() instanceof Mob riding ? riding.getMoveControl() : this.moveControl; } diff --git a/net/minecraft/world/entity/PathfinderMob.java b/net/minecraft/world/entity/PathfinderMob.java -index 71b0d444884848c4299cc4ef4f92f80f9b5fd516..ca585508c2405a0dfc2c60cfd025117689045e28 100644 +index c4b4a135f61955c2b87801772a2b31eeeb77bf45..9d12cc2d169f243ba23485e2782bca7064282a36 100644 --- a/net/minecraft/world/entity/PathfinderMob.java +++ b/net/minecraft/world/entity/PathfinderMob.java @@ -17,6 +17,8 @@ public abstract class PathfinderMob extends Mob { @@ -573,11 +573,11 @@ index 71b0d444884848c4299cc4ef4f92f80f9b5fd516..ca585508c2405a0dfc2c60cfd0251176 + public BlockPos movingTarget; public BlockPos getMovingTarget() { return movingTarget; } // Paper + - public float getWalkTargetValue(BlockPos pos) { + public float getWalkTargetValue(final BlockPos pos) { return this.getWalkTargetValue(pos, this.level()); } diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index d552e47aa38c61a8f78ed114a3433603c9658a24..674966c580220a4e0c83a628c763aaea8bfd0b1c 100644 +index 6bc2d38fb990628784deb5ee615e34a0fc320a47..844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -24,6 +24,7 @@ public class GoalSelector { @@ -586,10 +586,10 @@ index d552e47aa38c61a8f78ed114a3433603c9658a24..674966c580220a4e0c83a628c763aaea private final EnumSet disabledFlags = EnumSet.noneOf(Goal.Flag.class); + private int curRate; // Paper - EAR 2 - public void addGoal(int priority, Goal goal) { - this.availableGoals.add(new WrappedGoal(priority, goal)); + public void addGoal(final int prio, final Goal goal) { + this.availableGoals.add(new WrappedGoal(prio, goal)); @@ -33,6 +34,22 @@ public class GoalSelector { - this.availableGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal())); + this.availableGoals.removeIf(goal -> predicate.test(goal.getGoal())); } + // Paper start - EAR 2 @@ -599,7 +599,7 @@ index d552e47aa38c61a8f78ed114a3433603c9658a24..674966c580220a4e0c83a628c763aaea + } + + public boolean hasTasks() { -+ for (WrappedGoal task : this.availableGoals) { ++ for (final WrappedGoal task : this.availableGoals) { + if (task.isRunning()) { + return true; + } @@ -608,15 +608,15 @@ index d552e47aa38c61a8f78ed114a3433603c9658a24..674966c580220a4e0c83a628c763aaea + } + // Paper end - EAR 2 + - public void removeGoal(Goal goal) { - for (WrappedGoal wrappedGoal : this.availableGoals) { - if (wrappedGoal.getGoal() == goal && wrappedGoal.isRunning()) { + public void removeGoal(final Goal toRemove) { + for (WrappedGoal availableGoal : this.availableGoals) { + if (availableGoal.getGoal() == toRemove && availableGoal.isRunning()) { diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 3f780276be6766ef253c50212e06fd93a96b0caa..7e70c7bee633c54497d1cd2854dd60f4fb5ff160 100644 +index d46e0e3a4a7fc3bb3f1dd695d4cc563778b99db0..c6e9b155c2341c13d569f28f54f0c1d2d7313676 100644 --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java @@ -23,6 +23,14 @@ public abstract class MoveToBlockGoal extends Goal { - public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange) { + public MoveToBlockGoal(final PathfinderMob mob, final double speedModifier, final int searchRange) { this(mob, speedModifier, searchRange, 1); } + // Paper start - activation range improvements @@ -628,21 +628,21 @@ index 3f780276be6766ef253c50212e06fd93a96b0caa..7e70c7bee633c54497d1cd2854dd60f4 + } + // Paper end - public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange, int verticalSearchRange) { + public MoveToBlockGoal(final PathfinderMob mob, final double speedModifier, final int searchRange, final int verticalSearchRange) { this.mob = mob; @@ -113,6 +121,7 @@ public abstract class MoveToBlockGoal extends Goal { - mutableBlockPos.setWithOffset(blockPos, i4, i2 - 1, i5); - if (this.mob.isWithinHome(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) { - this.blockPos = mutableBlockPos; -+ this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper + pos.setWithOffset(mobPos, x, y - 1, z); + if (this.mob.isWithinHome(pos) && this.isValidTarget(this.mob.level(), pos)) { + this.blockPos = pos; ++ this.mob.movingTarget = pos == BlockPos.ZERO ? null : pos.immutable(); // Paper return true; } } diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java -index 768adc0205a2ec5221045c9c2ca0fdeec9f734b6..e82bb8f2d2b0e771dc371fd7e709116e1f5f204f 100644 +index a4f719c1b1b6a8920068ed8969a9e780420eade1..3791ffa6a14a1b2304780382e19f0e38a59f573f 100644 --- a/net/minecraft/world/entity/item/ItemEntity.java +++ b/net/minecraft/world/entity/item/ItemEntity.java -@@ -117,6 +117,29 @@ public class ItemEntity extends Entity implements TraceableEntity { +@@ -124,6 +124,29 @@ public class ItemEntity extends Entity implements TraceableEntity { return 0.04; } @@ -673,10 +673,10 @@ index 768adc0205a2ec5221045c9c2ca0fdeec9f734b6..e82bb8f2d2b0e771dc371fd7e709116e public void tick() { if (this.getItem().isEmpty()) { diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java -index 10a66bb3c093a1d31f3c985b418acb9232cc882c..89844d7e804cc8a2110b694e448bc5993991bea7 100644 +index e7df6fb302abc958608090e84052eccb3190ed95..df50e6ac986cd388f02d405186f2855e42638eac 100644 --- a/net/minecraft/world/entity/npc/villager/Villager.java +++ b/net/minecraft/world/entity/npc/villager/Villager.java -@@ -269,11 +269,35 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -244,11 +244,35 @@ public class Villager extends AbstractVillager implements VillagerDataHolder, Re return this.assignProfessionWhenSpawned; } @@ -700,29 +700,29 @@ index 10a66bb3c093a1d31f3c985b418acb9232cc882c..89844d7e804cc8a2110b694e448bc599 + // Paper end - EAR 2 + @Override - protected void customServerAiStep(ServerLevel level) { + protected void customServerAiStep(final ServerLevel level) { + // Paper start - EAR 2 + this.customServerAiStep(level, false); + } + protected void customServerAiStep(ServerLevel level, final boolean inactive) { + // Paper end - EAR 2 - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("villagerBrain"); + ProfilerFiller profiler = Profiler.get(); + profiler.push("villagerBrain"); - this.getBrain().tick(level, this); + if (!inactive) this.getBrain().tick(level, this); // Paper - EAR 2 - profilerFiller.pop(); + profiler.pop(); if (this.assignProfessionWhenSpawned) { this.assignProfessionWhenSpawned = false; -@@ -297,7 +321,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -272,7 +296,7 @@ public class Villager extends AbstractVillager implements VillagerDataHolder, Re this.lastTradedPlayer = null; } - if (!this.isNoAi() && this.random.nextInt(100) == 0) { + if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper - EAR 2 - Raid raidAt = level.getRaidAt(this.blockPosition()); - if (raidAt != null && raidAt.isActive() && !raidAt.isOver()) { + Raid raid = level.getRaidAt(this.blockPosition()); + if (raid != null && raid.isActive() && !raid.isOver()) { level.broadcastEntityEvent(this, EntityEvent.VILLAGER_SWEAT); -@@ -308,6 +332,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -283,6 +307,7 @@ public class Villager extends AbstractVillager implements VillagerDataHolder, Re this.stopTrading(); } @@ -731,11 +731,11 @@ index 10a66bb3c093a1d31f3c985b418acb9232cc882c..89844d7e804cc8a2110b694e448bc599 } diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -index 3ba7d5bcaa76442adbd681a15175ba178297e704..1b633d2eb77704fd9a6358f09ed368fab2a5b212 100644 +index c457a6b0935fa4dce20f93db79c27070ce147705..c9f7e68abccbc6b894a66b675952c973e22af8e6 100644 --- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -@@ -107,6 +107,21 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { - return super.shouldRender(x, y, z) && !this.isAttachedToEntity(); +@@ -111,6 +111,21 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { + return super.shouldRender(camX, camY, camZ) && !this.isAttachedToEntity(); } + // Paper start - EAR 2 @@ -757,11 +757,11 @@ index 3ba7d5bcaa76442adbd681a15175ba178297e704..1b633d2eb77704fd9a6358f09ed368fa public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/projectile/arrow/Arrow.java b/net/minecraft/world/entity/projectile/arrow/Arrow.java -index acef4aee02169a155fb2cc5195c33fb5fe29fa4d..bbbdf0048db1e806642ad96cce66818e524acc62 100644 +index 23a9a11f8b9397c91ac610d858b7c1c3810095c8..d8c84e718b9c9d142925e2569afbd72e462bf5ca 100644 --- a/net/minecraft/world/entity/projectile/arrow/Arrow.java +++ b/net/minecraft/world/entity/projectile/arrow/Arrow.java @@ -70,6 +70,16 @@ public class Arrow extends AbstractArrow { - builder.define(ID_EFFECT_COLOR, -1); + entityData.define(ID_EFFECT_COLOR, -1); } + // Paper start - EAR 2 @@ -778,12 +778,12 @@ index acef4aee02169a155fb2cc5195c33fb5fe29fa4d..bbbdf0048db1e806642ad96cce66818e public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java -index 4a6384a668546371f4ffa13927be4bd462d47c60..3c961b76769f16160caedce8ec32bb2a2561163f 100644 +index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584cefc776749 100644 --- a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java +++ b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java @@ -50,6 +50,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper - if (flag != this.isEnabled()) { - this.setEnabled(flag); + if (newEnabled != this.isEnabled()) { + this.setEnabled(newEnabled); } + this.immunize(); // Paper } @@ -796,16 +796,16 @@ index 4a6384a668546371f4ffa13927be4bd462d47c60..3c961b76769f16160caedce8ec32bb2a + this.immunize(); // Paper return true; } else { - for (ItemEntity itemEntity : this.level() + for (ItemEntity entity : this.level() .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) { - if (HopperBlockEntity.addItem(this, itemEntity)) { + if (HopperBlockEntity.addItem(this, entity)) { + this.immunize(); // Paper return true; } } @@ -142,4 +145,11 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper - public AbstractContainerMenu createMenu(int id, Inventory playerInventory) { - return new HopperMenu(id, playerInventory, this); + public AbstractContainerMenu createMenu(final int containerId, final Inventory inventory) { + return new HopperMenu(containerId, inventory, this); } + + // Paper start @@ -816,10 +816,10 @@ index 4a6384a668546371f4ffa13927be4bd462d47c60..3c961b76769f16160caedce8ec32bb2a + } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 49aca568407523d95d5801988fe153d71c9dc768..9e88d83b31129cc853afe60d841838852a33fc45 100644 +index 8c5725b83a82b4297aecebc5220e9b3160746923..ad39c0822f757216d817934ba18440c228dc6be3 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -149,6 +149,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -153,6 +153,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Nullable public List captureDrops; public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); @@ -833,13 +833,13 @@ index 49aca568407523d95d5801988fe153d71c9dc768..9e88d83b31129cc853afe60d84183885 public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot // Paper start - add paper world config diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -index 9f50e86a637aab8b5c34913e226807990c1891a4..bc42a6c678987a39b0a70a1a3e96eb90340ffea5 100644 +index ec01093094f1d4de2708791ae6a5545268a021ae..f904c587fafe7395473450f766354d874e36ebac 100644 --- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -@@ -152,6 +152,10 @@ public class PistonMovingBlockEntity extends BlockEntity { +@@ -159,6 +159,10 @@ public class PistonMovingBlockEntity extends BlockEntity { } - entity.setDeltaMovement(d1, d2, d3); + entity.setDeltaMovement(dx, dy, dz); + // Paper - EAR items stuck in slime pushed by a piston + entity.activatedTick = Math.max(entity.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 10); + entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 10); diff --git a/paper-server/patches/features/0004-Optimize-Voxel-Shape-Merging.patch b/paper-server/patches/features/0004-Optimize-Voxel-Shape-Merging.patch new file mode 100644 index 000000000000..48d0cd5cd4b9 --- /dev/null +++ b/paper-server/patches/features/0004-Optimize-Voxel-Shape-Merging.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sun, 3 May 2020 22:35:09 -0400 +Subject: [PATCH] Optimize Voxel Shape Merging + +This method shows up as super hot in profiler, and also a high "self" time. + +Upon analyzing, it appears most usages of this method fall down to the final +else statement of the nasty ternary. + +Upon even further analyzation, it appears then the majority of those have a +consistent list 1.... One with Infinity head and Tails. + +First optimization is to detect these infinite states and immediately return that +IndirectMerger so we can avoid testing the rest for most cases. + +Break the method into 2 to help the JVM promote inlining of this fast path. + +Then it was also noticed that IndirectMerger constructor is also a hotspot +with a high self time... + +Well, knowing that in most cases our list 1 is actualy the same value, it allows +us to know that with an infinite list1, the result on the merger is essentially +list2 as the final values. + +This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources) +and compute a deterministic result for the Merger values. + +Additionally, this lets us avoid even allocating new objects for this too, further +reducing memory usage. + +diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java +index 7e525297aaca8c18cf1669ab80040475029ff652..b342e4c0260fc5a64e5943e6342de0703233a99b 100644 +--- a/net/minecraft/world/phys/shapes/IndirectMerger.java ++++ b/net/minecraft/world/phys/shapes/IndirectMerger.java +@@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger { + private final int[] firstIndices; + private final int[] secondIndices; + private final int resultLength; ++ // Paper start ++ private static final int[] INFINITE_B_1 = {1, 1}; ++ private static final int[] INFINITE_B_0 = {0, 0}; ++ private static final int[] INFINITE_C = {0, 1}; ++ // Paper end + + public IndirectMerger(final DoubleList first, final DoubleList second, final boolean firstOnlyMatters, final boolean secondOnlyMatters) { + double lastValue = Double.NaN; + int firstSize = first.size(); + int secondSize = second.size(); + int capacity = firstSize + secondSize; ++ // Paper start - optimize common path of infinity doublelist ++ double tail = first.getDouble(firstSize - 1); ++ double head = first.getDouble(0); ++ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !firstOnlyMatters && !secondOnlyMatters && (firstSize == 2 || firstSize == 4)) { ++ this.result = second.toDoubleArray(); ++ this.resultLength = second.size(); ++ if (firstSize == 2) { ++ this.firstIndices = INFINITE_B_0; ++ } else { ++ this.firstIndices = INFINITE_B_1; ++ } ++ this.secondIndices = INFINITE_C; ++ return; ++ } ++ // Paper end + this.result = new double[capacity]; + this.firstIndices = new int[capacity]; + this.secondIndices = new int[capacity]; +diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java +index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..f9ec0ec86c3b45224ebc4f185a4c444df0013e47 100644 +--- a/net/minecraft/world/phys/shapes/Shapes.java ++++ b/net/minecraft/world/phys/shapes/Shapes.java +@@ -286,11 +286,26 @@ public final class Shapes { + } + + @VisibleForTesting +- protected static IndexMerger createIndexMerger( ++ private static IndexMerger createIndexMerger( // Paper - private + final int cost, final DoubleList first, final DoubleList second, final boolean firstOnlyMatters, final boolean secondOnlyMatters + ) { ++ // Paper start - fast track the most common scenario ++ // first is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause ++ // This is actually the most common path, so jump to it straight away ++ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) { ++ return new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters); ++ } ++ // Split out rest to hopefully inline the above ++ return lessCommonMerge(cost, first, second, firstOnlyMatters, secondOnlyMatters); ++ } ++ ++ private static IndexMerger lessCommonMerge( ++ final int cost, final DoubleList first, final DoubleList second, final boolean firstOnlyMatters, final boolean secondOnlyMatters ++ ) { ++ // Paper end - fast track the most common scenario + int firstSize = first.size() - 1; + int secondSize = second.size() - 1; ++ // Paper note - Rewrite below as optimized order if instead of nasty ternary + if (first instanceof CubePointRange && second instanceof CubePointRange) { + long size = lcm(firstSize, secondSize); + if (cost * size <= 256L) { +@@ -298,14 +313,21 @@ public final class Shapes { + } + } + +- if (first.getDouble(firstSize) < second.getDouble(0) - 1.0E-7) { ++ // Paper start - Identical happens more often than Disjoint ++ if (firstSize == secondSize && Objects.equals(first, second)) { ++ if (first instanceof IdenticalMerger firstMerger) { ++ return firstMerger; ++ } else if (second instanceof IdenticalMerger secondMerger) { ++ return secondMerger; ++ } ++ return new IdenticalMerger(first); ++ } else if (first.getDouble(firstSize) < second.getDouble(0) - 1.0E-7) { ++ // Paper end - Identical happens more often than Disjoint + return new NonOverlappingMerger(first, second, false); + } else if (second.getDouble(secondSize) < first.getDouble(0) - 1.0E-7) { + return new NonOverlappingMerger(second, first, true); + } else { +- return (IndexMerger)(firstSize == secondSize && Objects.equals(first, second) +- ? new IdenticalMerger(first) +- : new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters)); ++ return new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters); // Paper - Identical happens more often than Disjoint + } + } + diff --git a/paper-server/patches/features/0005-optimize-dirt-and-snow-spreading.patch b/paper-server/patches/features/0005-optimize-dirt-and-snow-spreading.patch new file mode 100644 index 000000000000..c09fba8774d1 --- /dev/null +++ b/paper-server/patches/features/0005-optimize-dirt-and-snow-spreading.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: lukas81298 +Date: Fri, 22 Jan 2021 21:50:18 +0100 +Subject: [PATCH] optimize dirt and snow spreading + + +diff --git a/net/minecraft/world/level/block/SpreadingSnowyBlock.java b/net/minecraft/world/level/block/SpreadingSnowyBlock.java +index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8507c3510 100644 +--- a/net/minecraft/world/level/block/SpreadingSnowyBlock.java ++++ b/net/minecraft/world/level/block/SpreadingSnowyBlock.java +@@ -27,8 +27,13 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { + protected abstract MapCodec codec(); + + private static boolean canStayAlive(final BlockState state, final LevelReader level, final BlockPos pos) { ++ // Paper start - Perf: optimize dirt and snow spreading ++ return canStayAlive(level.getChunk(pos), state, pos); ++ } ++ private static boolean canStayAlive(final net.minecraft.world.level.chunk.ChunkAccess chunk, final BlockState state, final BlockPos pos) { ++ // Paper end - Perf: optimize dirt and snow spreading + BlockPos above = pos.above(); +- BlockState aboveState = level.getBlockState(above); ++ BlockState aboveState = chunk.getBlockState(above); // Paper - Perf: optimize dirt and snow spreading + if (aboveState.is(Blocks.SNOW) && aboveState.getValue(SnowLayerBlock.LAYERS) == 1) { + return true; + } else if (aboveState.getFluidState().isFull()) { +@@ -40,8 +45,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { + } + + private static boolean canPropagate(final BlockState state, final LevelReader level, final BlockPos pos) { ++ // Paper start - Perf: optimize dirt and snow spreading ++ return canPropagate(level.getChunk(pos), state, pos); ++ } ++ ++ private static boolean canPropagate(final net.minecraft.world.level.chunk.ChunkAccess chunk, final BlockState state, final BlockPos pos) { ++ // Paper end - Perf: optimize dirt and snow spreading + BlockPos above = pos.above(); +- return canStayAlive(state, level, pos) && !level.getFluidState(above).is(FluidTags.WATER); ++ return canStayAlive(chunk, state, pos) && !chunk.getFluidState(above).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading + } + + @Override +@@ -50,7 +61,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { + Registry blocks = level.registryAccess().lookupOrThrow(Registries.BLOCK); + Optional baseBlock = blocks.getOptional(this.baseBlock); + if (!baseBlock.isEmpty()) { +- if (!canStayAlive(state, level, pos)) { ++ // Paper start - Perf: optimize dirt and snow spreading ++ final net.minecraft.world.level.chunk.ChunkAccess cachedChunk = level.getChunkIfLoaded(pos); ++ if (cachedChunk == null) { // Is this needed? ++ return; ++ } ++ ++ if (!canStayAlive(cachedChunk, state, pos)) { ++ // Paper end - Perf: optimize dirt and snow spreading + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, baseBlock.get().defaultBlockState()).isCancelled()) { + return; +@@ -63,8 +81,20 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { + + for (int i = 0; i < 4; i++) { + BlockPos testPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); +- if (level.getBlockState(testPos).is(baseBlock.get()) && canPropagate(defaultBlockState, level, testPos)) { +- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, testPos, defaultBlockState.setValue(SNOWY, isSnowySetting(level.getBlockState(testPos.above()))), Block.UPDATE_ALL); // CraftBukkit ++ // Paper start - Perf: optimize dirt and snow spreading ++ if (pos.getX() == testPos.getX() && pos.getY() == testPos.getY() && pos.getZ() == testPos.getZ()) { ++ continue; ++ } ++ ++ final net.minecraft.world.level.chunk.ChunkAccess access; ++ if (cachedChunk.locX == testPos.getX() >> 4 && cachedChunk.locZ == testPos.getZ() >> 4) { ++ access = cachedChunk; ++ } else { ++ access = level.getChunkAt(testPos); ++ } ++ if (access.getBlockState(testPos).is(baseBlock.get()) && SpreadingSnowyBlock.canPropagate(access, defaultBlockState, testPos)) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, testPos, defaultBlockState.setValue(SNOWY, isSnowySetting(access.getBlockState(testPos.above()))), Block.UPDATE_ALL); // CraftBukkit ++ // Paper end - Perf: optimize dirt and snow spreading + } + } + } diff --git a/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch b/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch index 86b04d15d7f5..c854b6350b4f 100644 --- a/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch +++ b/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Use Velocity compression and cipher natives diff --git a/net/minecraft/network/CipherDecoder.java b/net/minecraft/network/CipherDecoder.java -index b284b0b9907743a1736c95a4d111a727b789fc94..1467be3de89009529471c1cf4db2590128a6d792 100644 +index e134f0e82d16528da8a6a4af976f98514e5cecc5..034480cac0482355e0be4240214422476bd880ff 100644 --- a/net/minecraft/network/CipherDecoder.java +++ b/net/minecraft/network/CipherDecoder.java @@ -7,14 +7,30 @@ import java.util.List; @@ -15,21 +15,21 @@ index b284b0b9907743a1736c95a4d111a727b789fc94..1467be3de89009529471c1cf4db25901 - private final CipherBase cipher; + private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher -- public CipherDecoder(Cipher cipher) { +- public CipherDecoder(final Cipher cipher) { - this.cipher = new CipherBase(cipher); -+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher ++ public CipherDecoder(final com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher + this.cipher = cipher; // Paper - Use Velocity cipher } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { -- out.add(this.cipher.decipher(ctx, in)); + protected void decode(final ChannelHandlerContext ctx, final ByteBuf msg, final List out) throws Exception { +- out.add(this.cipher.decipher(ctx, msg)); + // Paper start - Use Velocity cipher -+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.cipher, in); ++ final ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.cipher, msg); + try { + this.cipher.process(compatible); + out.add(compatible); -+ } catch (Exception e) { ++ } catch (final Exception e) { + compatible.release(); // compatible will never be used if we throw an exception + throw e; + } @@ -38,13 +38,13 @@ index b284b0b9907743a1736c95a4d111a727b789fc94..1467be3de89009529471c1cf4db25901 + + // Paper start - Use Velocity cipher + @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) { ++ public void handlerRemoved(final ChannelHandlerContext ctx) { + this.cipher.close(); + } + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/CipherEncoder.java b/net/minecraft/network/CipherEncoder.java -index 8f0d47bf46bb5ddf61a84c43891a8dbc1e9f04e1..08363d710fb9c9d91967919b85fdd722e64d4d12 100644 +index 0003a548fe4a48ecfe3534f3de309a920568b773..fae764ffd6858c920cafd2fba4444793b4a83536 100644 --- a/net/minecraft/network/CipherEncoder.java +++ b/net/minecraft/network/CipherEncoder.java @@ -5,15 +5,31 @@ import io.netty.channel.ChannelHandlerContext; @@ -56,22 +56,22 @@ index 8f0d47bf46bb5ddf61a84c43891a8dbc1e9f04e1..08363d710fb9c9d91967919b85fdd722 +public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder { // Paper - Use Velocity cipher; change superclass + private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher -- public CipherEncoder(Cipher cipher) { +- public CipherEncoder(final Cipher cipher) { - this.cipher = new CipherBase(cipher); -+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher ++ public CipherEncoder(final com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher + this.cipher = cipher; // Paper - Use Velocity cipher } + // Paper start - Use Velocity cipher @Override -- protected void encode(ChannelHandlerContext ctx, ByteBuf message, ByteBuf out) throws Exception { -- this.cipher.encipher(message, out); -+ protected void encode(ChannelHandlerContext ctx, ByteBuf message, java.util.List list) throws Exception { -+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.cipher, message); +- protected void encode(final ChannelHandlerContext ctx, final ByteBuf msg, final ByteBuf out) throws Exception { +- this.cipher.encipher(msg, out); ++ protected void encode(final ChannelHandlerContext ctx, final ByteBuf msg, final java.util.List out) throws Exception { ++ final ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.cipher, msg); + try { + this.cipher.process(compatible); -+ list.add(compatible); -+ } catch (Exception e) { ++ out.add(compatible); ++ } catch (final Exception e) { + compatible.release(); // compatible will never be used if we throw an exception + throw e; + } @@ -80,13 +80,13 @@ index 8f0d47bf46bb5ddf61a84c43891a8dbc1e9f04e1..08363d710fb9c9d91967919b85fdd722 + + // Paper start - Use Velocity cipher + @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) { ++ public void handlerRemoved(final ChannelHandlerContext ctx) { + this.cipher.close(); + } + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/CompressionDecoder.java b/net/minecraft/network/CompressionDecoder.java -index 7e16d73f6fe852ca2dfd19cdd4592dedc9c54960..624c5d3d30282cf0d54faabc88d81ca0a9a8c785 100644 +index 2f660186f00414b37fa5c01d00c048173feaef13..fe3f0b59561e7b7236aba9cca2a13cee8955a933 100644 --- a/net/minecraft/network/CompressionDecoder.java +++ b/net/minecraft/network/CompressionDecoder.java @@ -12,14 +12,22 @@ import java.util.zip.Inflater; @@ -100,10 +100,10 @@ index 7e16d73f6fe852ca2dfd19cdd4592dedc9c54960..624c5d3d30282cf0d54faabc88d81ca0 + // Paper start - Use Velocity cipher + @io.papermc.paper.annotation.DoNotUse - public CompressionDecoder(int threshold, boolean validateDecompressed) { + public CompressionDecoder(final int threshold, final boolean validateDecompressed) { + this(null, threshold, validateDecompressed); + } -+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) { ++ public CompressionDecoder(final com.velocitypowered.natives.compression.VelocityCompressor compressor, final int threshold, final boolean validateDecompressed) { this.threshold = threshold; this.validateDecompressed = validateDecompressed; - this.inflater = new Inflater(); @@ -113,27 +113,26 @@ index 7e16d73f6fe852ca2dfd19cdd4592dedc9c54960..624c5d3d30282cf0d54faabc88d81ca0 } @Override -@@ -38,12 +46,40 @@ public class CompressionDecoder extends ByteToMessageDecoder { +@@ -38,12 +46,39 @@ public class CompressionDecoder extends ByteToMessageDecoder { } } + if (inflater != null) { // Paper - Use Velocity cipher; fallback to vanilla inflater this.setupInflaterInput(in); - ByteBuf byteBuf = this.inflate(ctx, i); + ByteBuf output = this.inflate(ctx, uncompressedLength); this.inflater.reset(); - out.add(byteBuf); + out.add(output); + return; // Paper - Use Velocity cipher + } // Paper - use velocity compression + + // Paper start - Use Velocity cipher -+ int claimedUncompressedSize = i; // OBFHELPER -+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, in); -+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, claimedUncompressedSize); ++ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, in); ++ final ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, uncompressedLength); + try { -+ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize); ++ this.compressor.inflate(compatibleIn, uncompressed, uncompressedLength); + out.add(uncompressed); + in.clear(); -+ } catch (Exception e) { ++ } catch (final Exception e) { + uncompressed.release(); + throw e; + } finally { @@ -145,22 +144,22 @@ index 7e16d73f6fe852ca2dfd19cdd4592dedc9c54960..624c5d3d30282cf0d54faabc88d81ca0 + + // Paper start - Use Velocity cipher + @Override -+ public void handlerRemoved0(ChannelHandlerContext ctx) { ++ public void handlerRemoved0(final ChannelHandlerContext ctx) { + if (this.compressor != null) { + this.compressor.close(); } } + // Paper end - Use Velocity cipher - private void setupInflaterInput(ByteBuf buffer) { - ByteBuffer byteBuffer; -@@ -79,7 +115,13 @@ public class CompressionDecoder extends ByteToMessageDecoder { + private void setupInflaterInput(final ByteBuf in) { + ByteBuffer input; +@@ -84,7 +119,13 @@ public class CompressionDecoder extends ByteToMessageDecoder { } } -- public void setThreshold(int threshold, boolean validateDecompressed) { +- public void setThreshold(final int threshold, final boolean validateDecompressed) { + // Paper start - Use Velocity cipher -+ public void setThreshold(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) { ++ public void setThreshold(final com.velocitypowered.natives.compression.VelocityCompressor compressor, final int threshold, final boolean validateDecompressed) { + if (this.compressor == null && compressor != null) { // Only re-configure once. Re-reconfiguring would require closing the native compressor. + this.compressor = compressor; + this.inflater = null; @@ -170,7 +169,7 @@ index 7e16d73f6fe852ca2dfd19cdd4592dedc9c54960..624c5d3d30282cf0d54faabc88d81ca0 this.validateDecompressed = validateDecompressed; } diff --git a/net/minecraft/network/CompressionEncoder.java b/net/minecraft/network/CompressionEncoder.java -index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7f749648d 100644 +index 319325e741cc314b84844bb49ea569aaf014f319..7d8986fe3c96cef829275ddd113bcd8a8d7ec583 100644 --- a/net/minecraft/network/CompressionEncoder.java +++ b/net/minecraft/network/CompressionEncoder.java @@ -6,17 +6,31 @@ import io.netty.handler.codec.MessageToByteEncoder; @@ -185,10 +184,10 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 private int threshold; + // Paper start - Use Velocity cipher - public CompressionEncoder(int threshold) { + public CompressionEncoder(final int threshold) { + this(null, threshold); + } -+ public CompressionEncoder(@javax.annotation.Nullable com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold) { ++ public CompressionEncoder(@javax.annotation.Nullable final com.velocitypowered.natives.compression.VelocityCompressor compressor, final int threshold) { this.threshold = threshold; - this.deflater = new Deflater(); + if (compressor == null) { @@ -203,19 +202,19 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 } @Override -- protected void encode(ChannelHandlerContext ctx, ByteBuf encodingByteBuf, ByteBuf byteBuf) { -+ protected void encode(ChannelHandlerContext ctx, ByteBuf encodingByteBuf, ByteBuf byteBuf) throws Exception { // Paper - Use Velocity cipher - int i = encodingByteBuf.readableBytes(); - if (i > 8388608) { - throw new IllegalArgumentException("Packet too big (is " + i + ", should be less than 8388608)"); +- protected void encode(final ChannelHandlerContext ctx, final ByteBuf uncompressed, final ByteBuf out) { ++ protected void encode(final ChannelHandlerContext ctx, final ByteBuf uncompressed, final ByteBuf out) throws Exception { // Paper - Use Velocity cipher + int uncompressedLength = uncompressed.readableBytes(); + if (uncompressedLength > 8388608) { + throw new IllegalArgumentException("Packet too big (is " + uncompressedLength + ", should be less than 8388608)"); @@ -25,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder { - VarInt.write(byteBuf, 0); - byteBuf.writeBytes(encodingByteBuf); + VarInt.write(out, 0); + out.writeBytes(uncompressed); } else { + if (this.deflater != null) { // Paper - Use Velocity cipher - byte[] bytes = new byte[i]; - encodingByteBuf.readBytes(bytes); - VarInt.write(byteBuf, bytes.length); + byte[] input = new byte[uncompressedLength]; + uncompressed.readBytes(input); + VarInt.write(out, input.length); @@ -37,6 +52,17 @@ public class CompressionEncoder extends MessageToByteEncoder { } @@ -224,10 +223,10 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 + return; + } + -+ VarInt.write(byteBuf, i); -+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, encodingByteBuf); ++ VarInt.write(out, uncompressedLength); ++ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, uncompressed); + try { -+ this.compressor.deflate(compatibleIn, byteBuf); ++ this.compressor.deflate(compatibleIn, out); + } finally { + compatibleIn.release(); + } @@ -235,13 +234,13 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 } } @@ -48,4 +74,31 @@ public class CompressionEncoder extends MessageToByteEncoder { - public void setThreshold(int threshold) { + public void setThreshold(final int threshold) { this.threshold = threshold; } + + // Paper start - Use Velocity cipher + @Override -+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception { ++ protected ByteBuf allocateBuffer(final ChannelHandlerContext ctx, final ByteBuf msg, final boolean preferDirect) throws Exception { + if (this.compressor != null) { + // We allocate bytes to be compressed plus 1 byte. This covers two cases: + // @@ -259,7 +258,7 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 + } + + @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) { ++ public void handlerRemoved(final ChannelHandlerContext ctx) { + if (this.compressor != null) { + this.compressor.close(); + } @@ -267,28 +266,28 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index 8817a2d6500d1bdce96d87dc8f7f364ccfa390e5..19ec939529eb638bdc4d7fd9260f161fae118314 100644 +index 8e6d1cc768edff5ed555dea7843156113558954a..20584e58d45e9dcdc4a3653133fcb4971a88d292 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java -@@ -728,11 +728,22 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -738,11 +738,22 @@ public class Connection extends SimpleChannelInboundHandler> { return connection; } -- public void setEncryptionKey(Cipher decryptingCipher, Cipher encryptingCipher) { +- public void setEncryptionKey(final Cipher decryptCipher, final Cipher encryptCipher) { - this.encrypted = true; -- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptingCipher)); -- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptingCipher)); +- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptCipher)); +- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptCipher)); + // Paper start - Use Velocity cipher -+ public void setEncryptionKey(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException { ++ public void setEncryptionKey(final javax.crypto.SecretKey key) throws net.minecraft.util.CryptException { + if (!this.encrypted) { + try { -+ com.velocitypowered.natives.encryption.VelocityCipher decryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key); -+ com.velocitypowered.natives.encryption.VelocityCipher encryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key); ++ final com.velocitypowered.natives.encryption.VelocityCipher decryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key); ++ final com.velocitypowered.natives.encryption.VelocityCipher encryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key); + + this.encrypted = true; + this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher)); + this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher)); -+ } catch (java.security.GeneralSecurityException e) { ++ } catch (final java.security.GeneralSecurityException e) { + throw new net.minecraft.util.CryptException(e); + } + } @@ -297,9 +296,9 @@ index 8817a2d6500d1bdce96d87dc8f7f364ccfa390e5..19ec939529eb638bdc4d7fd9260f161f public boolean isEncrypted() { return this.encrypted; -@@ -769,16 +780,17 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -779,16 +790,17 @@ public class Connection extends SimpleChannelInboundHandler> { // Paper end - add proper async disconnect - public void setupCompression(int threshold, boolean validateDecompressed) { + public void setupCompression(final int threshold, final boolean validateDecompressed) { if (threshold >= 0) { + com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder compressionDecoder) { @@ -319,10 +318,10 @@ index 8817a2d6500d1bdce96d87dc8f7f364ccfa390e5..19ec939529eb638bdc4d7fd9260f161f this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners } else { diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java -index 309845b28306dfa5946e79b80e5b1dde82dd68cd..33e1cdb00d648c992af03a976899253141314b27 100644 +index ea7512ac3866d4d02502a78c32e35ebc186b3838..9a51bc102bbebcee05f9a7e35df55be72ca8ee32 100644 --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -75,6 +75,11 @@ public class ServerConnectionListener { +@@ -76,6 +76,10 @@ public class ServerConnectionListener { LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled."); } // Paper end - Warn people with console access that HAProxy is in use. @@ -330,23 +329,22 @@ index 309845b28306dfa5946e79b80e5b1dde82dd68cd..33e1cdb00d648c992af03a9768992531 + ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity."); + ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity."); + // Paper end - Use Velocity cipher -+ this.channels .add( new ServerBootstrap() diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index ec5bd4568872c48addd26dd652868e0e5df57038..31bc0a105152a7f24a4126542bea7dbebc3e037c 100644 +index 8203765d5570644b4c8f6790f361bca2c7066b25..718f00ad9c587a4b0c12f351c10d462113f16ac3 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -245,11 +245,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, } - SecretKey secretKey = packet.getSecretKey(_private); -- Cipher cipher = Crypt.getCipher(2, secretKey); -- Cipher cipher1 = Crypt.getCipher(1, secretKey); - string = new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretKey)).toString(16); + SecretKey secretKey = packet.getSecretKey(serverPrivateKey); +- Cipher decryptCipher = Crypt.getCipher(2, secretKey); +- Cipher encryptCipher = Crypt.getCipher(1, secretKey); + digest = new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretKey)).toString(16); this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING; -- this.connection.setEncryptionKey(cipher, cipher1); +- this.connection.setEncryptionKey(decryptCipher, encryptCipher); + this.connection.setEncryptionKey(secretKey); // Paper - Use Velocity cipher } catch (CryptException var7) { throw new IllegalStateException("Protocol error", var7); diff --git a/paper-server/patches/features/0007-Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/paper-server/patches/features/0007-Optimize-GoalSelector-Goal.Flag-Set-operations.patch index 79957e9faa04..21a8d5e24dda 100644 --- a/paper-server/patches/features/0007-Optimize-GoalSelector-Goal.Flag-Set-operations.patch +++ b/paper-server/patches/features/0007-Optimize-GoalSelector-Goal.Flag-Set-operations.patch @@ -7,7 +7,7 @@ Optimise the stream.anyMatch statement to move to a bitset where we can replace the call with a single bitwise operation. diff --git a/net/minecraft/world/entity/ai/goal/Goal.java b/net/minecraft/world/entity/ai/goal/Goal.java -index a66c86066ca2eda10f0ef62e5197a765a994f250..f54bbe2e65b18f214266769c7a64144baafa9a58 100644 +index 5746eefd9e8fa851e74ccf6b5d889a9f8e6fc1e0..81fa892212f586e8cd7938556eeaa9f9dc2654aa 100644 --- a/net/minecraft/world/entity/ai/goal/Goal.java +++ b/net/minecraft/world/entity/ai/goal/Goal.java @@ -7,7 +7,15 @@ import net.minecraft.world.entity.Entity; @@ -30,12 +30,12 @@ index a66c86066ca2eda10f0ef62e5197a765a994f250..f54bbe2e65b18f214266769c7a64144b @@ -33,8 +41,13 @@ public abstract class Goal { } - public void setFlags(EnumSet flagSet) { + public void setFlags(final EnumSet requiredControlFlags) { - this.flags.clear(); -- this.flags.addAll(flagSet); +- this.flags.addAll(requiredControlFlags); + // Paper start - remove streams from GoalSelector + this.goalTypes.clear(); -+ this.goalTypes.addAllUnchecked(flagSet); ++ this.goalTypes.addAllUnchecked(requiredControlFlags); + if (this.goalTypes.size() == 0) { + this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR); + } @@ -59,17 +59,17 @@ index a66c86066ca2eda10f0ef62e5197a765a994f250..f54bbe2e65b18f214266769c7a64144b // Paper start - Mob Goal API public boolean hasFlag(final Goal.Flag flag) { - return this.flags.contains(flag); -+ return this.goalTypes.hasElement(flag); ++ return this.goalTypes.hasElement(flag); // Paper - remove streams from GoalSelector } public void addFlag(final Goal.Flag flag) { - this.flags.add(flag); -+ this.goalTypes.addUnchecked(flag); ++ this.goalTypes.addUnchecked(flag); // Paper - remove streams from GoalSelector } // Paper end - Mob Goal API diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 674966c580220a4e0c83a628c763aaea8bfd0b1c..859b859d29b637200cf7c9a0bd52d9f712413e3d 100644 +index 844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae..75d8953845b2e9acb62b19a859d0e39fd63533eb 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -23,7 +23,8 @@ public class GoalSelector { @@ -81,80 +81,80 @@ index 674966c580220a4e0c83a628c763aaea8bfd0b1c..859b859d29b637200cf7c9a0bd52d9f7 + private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from GoalSelector private int curRate; // Paper - EAR 2 - public void addGoal(int priority, Goal goal) { + public void addGoal(final int prio, final Goal goal) { @@ -60,18 +61,18 @@ public class GoalSelector { - this.availableGoals.removeIf(wrappedGoal1 -> wrappedGoal1.getGoal() == goal); + this.availableGoals.removeIf(goal -> goal.getGoal() == toRemove); } -- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet flag) { -- for (Goal.Flag flag1 : goal.getFlags()) { -- if (flag.contains(flag1)) { +- private static boolean goalContainsAnyFlags(final WrappedGoal goal, final EnumSet disabledFlags) { +- for (Goal.Flag flag : goal.getFlags()) { +- if (disabledFlags.contains(flag)) { - return true; - } - } - - return false; + // Paper start - Perf: optimize goal types -+ private static boolean goalContainsAnyFlags(WrappedGoal goal, ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet flags) { -+ return goal.getFlags().hasCommonElements(flags); ++ private static boolean goalContainsAnyFlags(final WrappedGoal goal, final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet disabledFlags) { ++ return goal.getFlags().hasCommonElements(disabledFlags); } - private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map flag) { -- for (Goal.Flag flag1 : goal.getFlags()) { + private static boolean goalCanBeReplacedForAllFlags(final WrappedGoal goal, final Map lockedFlags) { +- for (Goal.Flag flag : goal.getFlags()) { + long flagIterator = goal.getFlags().getBackingSet(); -+ int wrappedGoalSize = goal.getFlags().size(); -+ for (int i = 0; i < wrappedGoalSize; ++i) { -+ final Goal.Flag flag1 = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; ++ final int flagSize = goal.getFlags().size(); ++ for (int i = 0; i < flagSize; ++i) { ++ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; + flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); + // Paper end - Perf: optimize goal types - if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) { + if (!lockedFlags.getOrDefault(flag, NO_GOAL).canBeReplacedBy(goal)) { return false; } @@ -85,7 +86,7 @@ public class GoalSelector { - profilerFiller.push("goalCleanup"); + profiler.push("goalCleanup"); - for (WrappedGoal wrappedGoal : this.availableGoals) { -- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) { -+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams - wrappedGoal.stop(); + for (WrappedGoal goal : this.availableGoals) { +- if (goal.isRunning() && (goalContainsAnyFlags(goal, this.disabledFlags) || !goal.canContinueToUse())) { ++ if (goal.isRunning() && (goalContainsAnyFlags(goal, this.goalTypes) || !goal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams + goal.stop(); } } @@ -95,11 +96,14 @@ public class GoalSelector { - profilerFiller.push("goalUpdate"); - - for (WrappedGoal wrappedGoalx : this.availableGoals) { -- if (!wrappedGoalx.isRunning() -- && !goalContainsAnyFlags(wrappedGoalx, this.disabledFlags) -- && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags) -- && wrappedGoalx.canUse()) { -- for (Goal.Flag flag : wrappedGoalx.getFlags()) { + profiler.push("goalUpdate"); + + for (WrappedGoal goalx : this.availableGoals) { +- if (!goalx.isRunning() +- && !goalContainsAnyFlags(goalx, this.disabledFlags) +- && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags) +- && goalx.canUse()) { +- for (Goal.Flag flag : goalx.getFlags()) { + // Paper start -+ if (!wrappedGoalx.isRunning() && !goalContainsAnyFlags(wrappedGoalx, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags) && wrappedGoalx.canUse()) { -+ long flagIterator = wrappedGoalx.getFlags().getBackingSet(); -+ int wrappedGoalSize = wrappedGoalx.getFlags().size(); ++ if (!goalx.isRunning() && !goalContainsAnyFlags(goalx, this.goalTypes) && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags) && goalx.canUse()) { ++ long flagIterator = goalx.getFlags().getBackingSet(); ++ int wrappedGoalSize = goalx.getFlags().size(); + for (int i = 0; i < wrappedGoalSize; ++i) { + final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; + flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); + // Paper end - WrappedGoal wrappedGoal1 = this.lockedFlags.getOrDefault(flag, NO_GOAL); - wrappedGoal1.stop(); - this.lockedFlags.put(flag, wrappedGoalx); + WrappedGoal currentGoal = this.lockedFlags.getOrDefault(flag, NO_GOAL); + currentGoal.stop(); + this.lockedFlags.put(flag, goalx); @@ -131,11 +135,11 @@ public class GoalSelector { } - public void disableControlFlag(Goal.Flag flag) { + public void disableControlFlag(final Goal.Flag flag) { - this.disabledFlags.add(flag); + this.goalTypes.addUnchecked(flag); // Paper - remove streams from GoalSelector } - public void enableControlFlag(Goal.Flag flag) { + public void enableControlFlag(final Goal.Flag flag) { - this.disabledFlags.remove(flag); + this.goalTypes.removeUnchecked(flag); // Paper - remove streams from GoalSelector } - public void setControlFlag(Goal.Flag flag, boolean enabled) { + public void setControlFlag(final Goal.Flag flag, final boolean enabled) { diff --git a/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/net/minecraft/world/entity/ai/goal/WrappedGoal.java -index 4bdbd323b642ed3422948fe24780be8b503602dc..2c2ab6a1df9d3d23773e44ce4041cc1c21b55163 100644 +index 95d8a70deba7da2b5471afd8c70eeefa2db37ea3..0203405b8abefa82cf9cafd9bc0ab2a3ee866240 100644 --- a/net/minecraft/world/entity/ai/goal/WrappedGoal.java +++ b/net/minecraft/world/entity/ai/goal/WrappedGoal.java @@ -69,7 +69,7 @@ public class WrappedGoal extends Goal { diff --git a/paper-server/patches/features/0009-Handle-Oversized-block-entities-in-chunks.patch b/paper-server/patches/features/0008-Handle-Oversized-block-entities-in-chunks.patch similarity index 90% rename from paper-server/patches/features/0009-Handle-Oversized-block-entities-in-chunks.patch rename to paper-server/patches/features/0008-Handle-Oversized-block-entities-in-chunks.patch index d1f3ce49f7b9..66abb1d74e1c 100644 --- a/paper-server/patches/features/0009-Handle-Oversized-block-entities-in-chunks.patch +++ b/paper-server/patches/features/0008-Handle-Oversized-block-entities-in-chunks.patch @@ -9,7 +9,7 @@ creating too large of a packet to sed. Co-authored-by: Spottedleaf diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java -index de234f220ba09ad9b5e0c8215b49d20ca51d0ac7..e216a9d70be5a3da7c03ee99a8986391ef2dbd5b 100644 +index 2bfc4cb47fc51345fc733b6ab3b19ace4f8bc171..dad2b89355b05900251955d015451fe195bfdb49 100644 --- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -32,6 +32,14 @@ public class ClientboundLevelChunkPacketData { @@ -25,7 +25,7 @@ index de234f220ba09ad9b5e0c8215b49d20ca51d0ac7..e216a9d70be5a3da7c03ee99a8986391 + } + // Paper end - Handle oversized block entities in chunks - public ClientboundLevelChunkPacketData(LevelChunk levelChunk) { + public ClientboundLevelChunkPacketData(final LevelChunk levelChunk) { this.heightmaps = levelChunk.getHeightmaps() @@ -41,8 +49,18 @@ public class ClientboundLevelChunkPacketData { this.buffer = new byte[calculateChunkSize(levelChunk)]; @@ -47,10 +47,10 @@ index de234f220ba09ad9b5e0c8215b49d20ca51d0ac7..e216a9d70be5a3da7c03ee99a8986391 } } diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java -index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..fdd164cd45a26c7ef25f1153ab8985ba50c01b14 100644 +index be8ba1425b55a4948afb3f86c0feb3e2b1c2b561..a94e6ca1d396b6b0781de5d550c4a804274ee003 100644 --- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java +++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java -@@ -71,4 +71,11 @@ public class ClientboundLevelChunkWithLightPacket implements Packet -Date: Sun, 3 May 2020 22:35:09 -0400 -Subject: [PATCH] Optimize Voxel Shape Merging - -This method shows up as super hot in profiler, and also a high "self" time. - -Upon analyzing, it appears most usages of this method fall down to the final -else statement of the nasty ternary. - -Upon even further analyzation, it appears then the majority of those have a -consistent list 1.... One with Infinity head and Tails. - -First optimization is to detect these infinite states and immediately return that -VoxelShapeMergerList so we can avoid testing the rest for most cases. - -Break the method into 2 to help the JVM promote inlining of this fast path. - -Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot -with a high self time... - -Well, knowing that in most cases our list 1 is actualy the same value, it allows -us to know that with an infinite list1, the result on the merger is essentially -list2 as the final values. - -This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources) -and compute a deterministic result for the MergerList values. - -Additionally, this lets us avoid even allocating new objects for this too, further -reducing memory usage. - -diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java -index 60b56a5086b8aad0fad693f686b89138b3a4c80d..5b079ec43c259368d0eed4e8385880712abda4f7 100644 ---- a/net/minecraft/world/phys/shapes/IndirectMerger.java -+++ b/net/minecraft/world/phys/shapes/IndirectMerger.java -@@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger { - private final int[] firstIndices; - private final int[] secondIndices; - private final int resultLength; -+ // Paper start -+ private static final int[] INFINITE_B_1 = {1, 1}; -+ private static final int[] INFINITE_B_0 = {0, 0}; -+ private static final int[] INFINITE_C = {0, 1}; -+ // Paper end - - public IndirectMerger(DoubleList lower, DoubleList upper, boolean excludeUpper, boolean excludeLower) { - double d = Double.NaN; - int size = lower.size(); - int size1 = upper.size(); - int i = size + size1; -+ // Paper start - optimize common path of infinity doublelist -+ double tail = lower.getDouble(size - 1); -+ double head = lower.getDouble(0); -+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !excludeUpper && !excludeLower && (size == 2 || size == 4)) { -+ this.result = upper.toDoubleArray(); -+ this.resultLength = upper.size(); -+ if (size == 2) { -+ this.firstIndices = INFINITE_B_0; -+ } else { -+ this.firstIndices = INFINITE_B_1; -+ } -+ this.secondIndices = INFINITE_C; -+ return; -+ } -+ // Paper end - this.result = new double[i]; - this.firstIndices = new int[i]; - this.secondIndices = new int[i]; -diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java -index ac4bb789df88c07ea38d20700dccb6571e3ea58d..fc2b393d24fef8ce3a74d38d0937bfe5604eae87 100644 ---- a/net/minecraft/world/phys/shapes/Shapes.java -+++ b/net/minecraft/world/phys/shapes/Shapes.java -@@ -346,9 +346,22 @@ public final class Shapes { - } - - @VisibleForTesting -- protected static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { -+ private static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { // Paper - private -+ // Paper start - fast track the most common scenario -+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause -+ // This is actually the most common path, so jump to it straight away -+ if (list1.getDouble(0) == Double.NEGATIVE_INFINITY && list1.getDouble(list1.size() - 1) == Double.POSITIVE_INFINITY) { -+ return new IndirectMerger(list1, list2, excludeUpper, excludeLower); -+ } -+ // Split out rest to hopefully inline the above -+ return lessCommonMerge(size, list1, list2, excludeUpper, excludeLower); -+ } -+ -+ private static IndexMerger lessCommonMerge(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { -+ // Paper end - fast track the most common scenario - int i = list1.size() - 1; - int i1 = list2.size() - 1; -+ // Paper note - Rewrite below as optimized order if instead of nasty ternary - if (list1 instanceof CubePointRange && list2 instanceof CubePointRange) { - long l = lcm(i, i1); - if (size * l <= 256L) { -@@ -356,14 +369,21 @@ public final class Shapes { - } - } - -- if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) { -+ // Paper start - Identical happens more often than Disjoint -+ if (i == i1 && Objects.equals(list1, list2)) { -+ if (list1 instanceof IdenticalMerger) { -+ return (IndexMerger) list1; -+ } else if (list2 instanceof IdenticalMerger) { -+ return (IndexMerger) list2; -+ } -+ return new IdenticalMerger(list1); -+ } else if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) { -+ // Paper end - Identical happens more often than Disjoint - return new NonOverlappingMerger(list1, list2, false); - } else if (list2.getDouble(i1) < list1.getDouble(0) - 1.0E-7) { - return new NonOverlappingMerger(list2, list1, true); - } else { -- return (IndexMerger)(i == i1 && Objects.equals(list1, list2) -- ? new IdenticalMerger(list1) -- : new IndirectMerger(list1, list2, excludeUpper, excludeLower)); -+ return new IndirectMerger(list1, list2, excludeUpper, excludeLower); // Paper - Identical happens more often than Disjoint - } - } - diff --git a/paper-server/patches/features/0011-Optimize-Bit-Operations-by-inlining.patch b/paper-server/patches/features/0009-Optimize-Bit-Operations-by-inlining.patch similarity index 51% rename from paper-server/patches/features/0011-Optimize-Bit-Operations-by-inlining.patch rename to paper-server/patches/features/0009-Optimize-Bit-Operations-by-inlining.patch index f7f00fa36ba6..9e82587bb687 100644 --- a/paper-server/patches/features/0011-Optimize-Bit-Operations-by-inlining.patch +++ b/paper-server/patches/features/0009-Optimize-Bit-Operations-by-inlining.patch @@ -7,10 +7,10 @@ Inline bit operations and reduce instruction count to make these hot operations faster diff --git a/net/minecraft/core/BlockPos.java b/net/minecraft/core/BlockPos.java -index e694be770b49268b77566c3fd7b111298fb8920b..e87473fcb36e18d960ef3e4082995785d64b9c0f 100644 +index 0eef9e01cbfc7e968379f5d8526bcabb00446224..f397aa6fe43a906ffb92d65331831d5ef5c7cb2a 100644 --- a/net/minecraft/core/BlockPos.java +++ b/net/minecraft/core/BlockPos.java -@@ -49,15 +49,17 @@ public class BlockPos extends Vec3i { +@@ -48,15 +48,17 @@ public class BlockPos extends Vec3i { } }; public static final BlockPos ZERO = new BlockPos(0, 0, 0); @@ -34,79 +34,79 @@ index e694be770b49268b77566c3fd7b111298fb8920b..e87473fcb36e18d960ef3e4082995785 + public static final int MAX_HORIZONTAL_COORDINATE = 33554431; + // Paper end - Optimize Bit Operations by inlining - public BlockPos(int x, int y, int z) { + public BlockPos(final int x, final int y, final int z) { super(x, y, z); -@@ -67,28 +69,29 @@ public class BlockPos extends Vec3i { - this(vector.getX(), vector.getY(), vector.getZ()); +@@ -66,28 +68,29 @@ public class BlockPos extends Vec3i { + this(vec3i.getX(), vec3i.getY(), vec3i.getZ()); } + public static long getAdjacent(int baseX, int baseY, int baseZ, Direction direction) { return asLong(baseX + direction.getStepX(), baseY + direction.getStepY(), baseZ + direction.getStepZ()); } // Paper - public static long offset(long pos, Direction direction) { - return offset(pos, direction.getStepX(), direction.getStepY(), direction.getStepZ()); + public static long offset(final long blockNode, final Direction offset) { + return offset(blockNode, offset.getStepX(), offset.getStepY(), offset.getStepZ()); } - public static long offset(long pos, int dx, int dy, int dz) { -- return asLong(getX(pos) + dx, getY(pos) + dy, getZ(pos) + dz); -+ return asLong((int) (pos >> 38) + dx, (int) ((pos << 52) >> 52) + dy, (int) ((pos << 26) >> 38) + dz); // Paper - simplify/inline + public static long offset(final long blockNode, final int stepX, final int stepY, final int stepZ) { +- return asLong(getX(blockNode) + stepX, getY(blockNode) + stepY, getZ(blockNode) + stepZ); ++ return asLong((int) (blockNode >> 38) + stepX, (int) ((blockNode << 52) >> 52) + stepY, (int) ((blockNode << 26) >> 38) + stepZ); // Paper - simplify/inlin } - public static int getX(long packedPos) { -- return (int)(packedPos << 64 - X_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH); -+ return (int) (packedPos >> 38); // Paper - simplify/inline + public static int getX(final long blockNode) { +- return (int)(blockNode << 64 - X_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH); ++ return (int) (blockNode >> 38); // Paper - simplify/inline } - public static int getY(long packedPos) { -- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH); -+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline + public static int getY(final long blockNode) { +- return (int)(blockNode << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH); ++ return (int) ((blockNode << 52) >> 52); // Paper - simplify/inline } - public static int getZ(long packedPos) { -- return (int)(packedPos << 64 - Z_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH); -+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline + public static int getZ(final long blockNode) { +- return (int)(blockNode << 64 - Z_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH); ++ return (int) ((blockNode << 26) >> 38); // Paper - simplify/inline } - public static BlockPos of(long packedPos) { -- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos)); -+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline + public static BlockPos of(final long blockNode) { +- return new BlockPos(getX(blockNode), getY(blockNode), getZ(blockNode)); ++ return new BlockPos((int) (blockNode >> 38), (int) ((blockNode << 52) >> 52), (int) ((blockNode << 26) >> 38)); // Paper - simplify/inline } - public static BlockPos containing(double x, double y, double z) { -@@ -112,10 +115,7 @@ public class BlockPos extends Vec3i { + public static BlockPos containing(final double x, final double y, final double z) { +@@ -111,10 +114,7 @@ public class BlockPos extends Vec3i { } - public static long asLong(int x, int y, int z) { -- long l = 0L; -- l |= (x & PACKED_X_MASK) << X_OFFSET; -- l |= (y & PACKED_Y_MASK) << 0; -- return l | (z & PACKED_Z_MASK) << Z_OFFSET; -+ return ((x & 67108863L) << 38) | ((y & 4095L)) | ((z & 67108863L) << 12); // Paper - inline constants and simplify + public static long asLong(final int x, final int y, final int z) { +- long node = 0L; +- node |= (x & PACKED_X_MASK) << X_OFFSET; +- node |= (y & PACKED_Y_MASK) << 0; +- return node | (z & PACKED_Z_MASK) << Z_OFFSET; ++ return ((x & 67108863L) << 38) | ((y & 4095L)) | ((z & 67108863L) << 12); // Paper - inline constants and simplify } - public static long getFlatIndex(long packedPos) { + public static long getFlatIndex(final long neighborBlockNode) { diff --git a/net/minecraft/core/SectionPos.java b/net/minecraft/core/SectionPos.java -index a31e7af294d574c2c9711de75d33022ed86984c4..7a9889333d6a82a58731a54c612bddfaa1a3ec6a 100644 +index e6595167980d93772088f63ba6dd0423489d90c4..96439461ea272b9f5101365a094f8eec1e28d582 100644 --- a/net/minecraft/core/SectionPos.java +++ b/net/minecraft/core/SectionPos.java @@ -42,7 +42,7 @@ public class SectionPos extends Vec3i { } - public static SectionPos of(BlockPos pos) { + public static SectionPos of(final BlockPos pos) { - return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ())); + return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper } - public static SectionPos of(ChunkPos chunkPos, int y) { + public static SectionPos of(final ChunkPos pos, final int sectionY) { @@ -58,7 +58,7 @@ public class SectionPos extends Vec3i { } - public static SectionPos of(long packed) { -- return new SectionPos(x(packed), y(packed), z(packed)); -+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper + public static SectionPos of(final long sectionNode) { +- return new SectionPos(x(sectionNode), y(sectionNode), z(sectionNode)); ++ return new SectionPos((int) (sectionNode >> 42), (int) (sectionNode << 44 >> 44), (int) (sectionNode << 22 >> 42)); // Paper } - public static SectionPos bottomOf(ChunkAccess chunk) { + public static SectionPos bottomOf(final ChunkAccess chunk) { @@ -69,8 +69,16 @@ public class SectionPos extends Vec3i { - return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ()); + return offset(sectionNode, offset.getStepX(), offset.getStepY(), offset.getStepZ()); } + // Paper start @@ -117,24 +117,24 @@ index a31e7af294d574c2c9711de75d33022ed86984c4..7a9889333d6a82a58731a54c612bddfa + return (((long) (x + direction.getStepX()) & 4194303L) << 42) | (((long) ((y) + direction.getStepY()) & 1048575L)) | (((long) (z + direction.getStepZ()) & 4194303L) << 20); + } + // Paper end - public static long offset(long packed, int dx, int dy, int dz) { -- return asLong(x(packed) + dx, y(packed) + dy, z(packed) + dz); -+ return (((long) ((int) (packed >> 42) + dx) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + dy) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + dz) & 4194303L) << 20); // Simplify to reduce instruction count + public static long offset(final long sectionNode, final int stepX, final int stepY, final int stepZ) { +- return asLong(x(sectionNode) + stepX, y(sectionNode) + stepY, z(sectionNode) + stepZ); ++ return (((long) ((int) (sectionNode >> 42) + stepX) & 4194303L) << 42) | (((long) ((int) (sectionNode << 44 >> 44) + stepY) & 1048575L)) | (((long) ((int) (sectionNode << 22 >> 42) + stepZ) & 4194303L) << 20); // Paper - Simplify to reduce instruction count } - public static int posToSectionCoord(double pos) { + public static int posToSectionCoord(final double pos) { @@ -90,10 +98,7 @@ public class SectionPos extends Vec3i { } - public static short sectionRelativePos(BlockPos pos) { -- int relativeBlockPosX = sectionRelative(pos.getX()); -- int relativeBlockPosY = sectionRelative(pos.getY()); -- int relativeBlockPosZ = sectionRelative(pos.getZ()); -- return (short)(relativeBlockPosX << 8 | relativeBlockPosZ << 4 | relativeBlockPosY << 0); + public static short sectionRelativePos(final BlockPos pos) { +- int x = sectionRelative(pos.getX()); +- int y = sectionRelative(pos.getY()); +- int z = sectionRelative(pos.getZ()); +- return (short)(x << 8 | z << 4 | y << 0); + return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline } - public static int sectionRelativeX(short x) { + public static int sectionRelativeX(final short relative) { @@ -156,16 +161,16 @@ public class SectionPos extends Vec3i { return this.getZ(); } @@ -158,16 +158,18 @@ index a31e7af294d574c2c9711de75d33022ed86984c4..7a9889333d6a82a58731a54c612bddfa } public int maxBlockX() { -@@ -181,7 +186,7 @@ public class SectionPos extends Vec3i { +@@ -181,9 +186,7 @@ public class SectionPos extends Vec3i { } - public static long blockToSection(long pos) { -- return asLong(blockToSectionCoord(BlockPos.getX(pos)), blockToSectionCoord(BlockPos.getY(pos)), blockToSectionCoord(BlockPos.getZ(pos))); -+ return (((long) (int) (pos >> 42) & 4194303L) << 42) | (((long) (int) ((pos << 52) >> 56) & 1048575L)) | (((long) (int) ((pos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count + public static long blockToSection(final long blockNode) { +- return asLong( +- blockToSectionCoord(BlockPos.getX(blockNode)), blockToSectionCoord(BlockPos.getY(blockNode)), blockToSectionCoord(BlockPos.getZ(blockNode)) +- ); ++ return (((long) (int) (blockNode >> 42) & 4194303L) << 42) | (((long) (int) ((blockNode << 52) >> 56) & 1048575L)) | (((long) (int) ((blockNode << 26) >> 42) & 4194303L) << 20); // Paper - Simplify to reduce instruction count } - public static long getZeroNode(int x, int z) { -@@ -213,15 +218,17 @@ public class SectionPos extends Vec3i { + public static long getZeroNode(final int x, final int z) { +@@ -215,15 +218,17 @@ public class SectionPos extends Vec3i { return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ())); } @@ -176,11 +178,11 @@ index a31e7af294d574c2c9711de75d33022ed86984c4..7a9889333d6a82a58731a54c612bddfa + return (((long) (x >> 4) & 4194303L) << 42) | (((long) (y >> 4) & 1048575L)) | (((long) (z >> 4) & 4194303L) << 20); + } + // Paper end - public static long asLong(int x, int y, int z) { -- long l = 0L; -- l |= (x & 4194303L) << 42; -- l |= (y & 1048575L) << 0; -- return l | (z & 4194303L) << 20; + public static long asLong(final int x, final int y, final int z) { +- long node = 0L; +- node |= (x & 4194303L) << 42; +- node |= (y & 1048575L) << 0; +- return node | (z & 4194303L) << 20; + return ((x & 4194303L) << 42) | ((y & 1048575L)) | ((z & 4194303L) << 20); // Paper - Simplify to reduce instruction count } @@ -190,15 +192,15 @@ index a31e7af294d574c2c9711de75d33022ed86984c4..7a9889333d6a82a58731a54c612bddfa } @Override -@@ -234,10 +241,7 @@ public class SectionPos extends Vec3i { +@@ -236,10 +241,7 @@ public class SectionPos extends Vec3i { } - public static Stream cube(SectionPos center, int radius) { -- int sectionX = center.x(); -- int sectionY = center.y(); -- int sectionZ = center.z(); -- return betweenClosedStream(sectionX - radius, sectionY - radius, sectionZ - radius, sectionX + radius, sectionY + radius, sectionZ + radius); + public static Stream cube(final SectionPos center, final int radius) { +- int x = center.x(); +- int y = center.y(); +- int z = center.z(); +- return betweenClosedStream(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius); + return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline } - public static Stream aroundChunk(ChunkPos chunkPos, int radius, int minY, int maxY) { + public static Stream aroundChunk(final ChunkPos center, final int radius, final int minSection, final int maxSection) { diff --git a/paper-server/patches/features/0010-Remove-streams-from-hot-code.patch b/paper-server/patches/features/0010-Remove-streams-from-hot-code.patch new file mode 100644 index 000000000000..1406492849c8 --- /dev/null +++ b/paper-server/patches/features/0010-Remove-streams-from-hot-code.patch @@ -0,0 +1,190 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Roy <10731363+JRoy@users.noreply.github.com> +Date: Wed, 1 Jul 2020 18:01:49 -0400 +Subject: [PATCH] Remove streams from hot code + +Co-authored-by: Bjarne Koll +Co-authored-by: Spottedleaf + +diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java +index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e48d4dd9a6 100644 +--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java ++++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java +@@ -69,7 +69,7 @@ public class GateBehavior implements BehaviorControl + if (this.hasRequiredMemories(body)) { + this.status = Behavior.Status.RUNNING; + this.orderPolicy.apply(this.behaviors); +- this.runningPolicy.apply(this.behaviors.stream(), level, body, timestamp); ++ this.runningPolicy.apply(this.behaviors, level, body, timestamp); // Paper - Perf: Remove streams from hot code + return true; + } else { + return false; +@@ -78,8 +78,14 @@ public class GateBehavior implements BehaviorControl + + @Override + public final void tickOrStop(final ServerLevel level, final E body, final long timestamp) { +- this.behaviors.stream().filter(goal -> goal.getStatus() == Behavior.Status.RUNNING).forEach(goal -> goal.tickOrStop(level, body, timestamp)); +- if (this.behaviors.stream().noneMatch(g -> g.getStatus() == Behavior.Status.RUNNING)) { ++ // Paper start - Perf: Remove streams from hot code ++ for (final BehaviorControl behavior : this.behaviors) { ++ if (behavior.getStatus() == Behavior.Status.RUNNING) { ++ behavior.tickOrStop(level, body, timestamp); ++ } ++ } ++ // Paper end - Perf: Remove streams from hot code ++ if (this.behaviors.stream().noneMatch(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)) { + this.doStop(level, body, timestamp); + } + } +@@ -87,8 +93,16 @@ public class GateBehavior implements BehaviorControl + @Override + public final void doStop(final ServerLevel level, final E body, final long timestamp) { + this.status = Behavior.Status.STOPPED; +- this.behaviors.stream().filter(goal -> goal.getStatus() == Behavior.Status.RUNNING).forEach(goal -> goal.doStop(level, body, timestamp)); +- this.exitErasedMemories.forEach(body.getBrain()::eraseMemory); ++ // Paper start - Perf: Remove streams from hot code ++ for (final BehaviorControl behavior : this.behaviors) { ++ if (behavior.getStatus() == Behavior.Status.RUNNING) { ++ behavior.doStop(level, body, timestamp); ++ } ++ } ++ for (final MemoryModuleType exitErasedMemory : this.exitErasedMemories) { ++ body.getBrain().eraseMemory(exitErasedMemory); ++ } ++ // Paper end - Perf: Remove streams from hot code + } + + @Override +@@ -118,24 +132,36 @@ public class GateBehavior implements BehaviorControl + + public static enum RunningPolicy { + RUN_ONE { ++ // Paper start - Perf: Remove streams from hot code + @Override + public void apply( +- final Stream> behaviors, final ServerLevel level, final E body, final long timestamp ++ final ShufflingList> behaviors, final ServerLevel level, final E body, final long timestamp + ) { +- behaviors.filter(goal -> goal.getStatus() == Behavior.Status.STOPPED).filter(goal -> goal.tryStart(level, body, timestamp)).findFirst(); ++ for (final BehaviorControl behavior : behaviors) { ++ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(level, body, timestamp)) { ++ break; ++ } ++ } ++ // Paper end - Perf: Remove streams from hot code + } + }, + TRY_ALL { ++ // Paper start - Perf: Remove streams from hot code + @Override + public void apply( +- final Stream> behaviors, final ServerLevel level, final E body, final long timestamp ++ final ShufflingList> behaviors, final ServerLevel level, final E body, final long timestamp + ) { +- behaviors.filter(goal -> goal.getStatus() == Behavior.Status.STOPPED).forEach(goal -> goal.tryStart(level, body, timestamp)); ++ for (final BehaviorControl behavior : behaviors) { ++ if (behavior.getStatus() == Behavior.Status.STOPPED) { ++ behavior.tryStart(level, body, timestamp); ++ } ++ } ++ // Paper end - Perf: Remove streams from hot code + } + }; + + public abstract void apply( +- final Stream> behaviors, final ServerLevel level, final E body, final long timestamp ++ final ShufflingList> behaviors, final ServerLevel level, final E body, final long timestamp // Paper - Perf: Remove streams from hot code + ); + } + } +diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java +index d6fcd4f15694e5088de22042c0e4971f3ee3b2a1..45e05fb6de45366bdb3096a3907030c2f6f04f70 100644 +--- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java ++++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java +@@ -28,7 +28,7 @@ import net.minecraft.util.VisibleForDebug; + public class GossipContainer { + public static final Codec CODEC = GossipContainer.GossipEntry.CODEC + .listOf() +- .xmap(GossipContainer::new, container -> container.unpack().toList()); ++ .xmap(GossipContainer::new, container -> container.decompress()); // Paper - Perf: Remove streams from hot code + public static final int DISCARD_THRESHOLD = 2; + public final Map gossips = new HashMap<>(); + +@@ -65,8 +65,22 @@ public class GossipContainer { + return this.gossips.entrySet().stream().flatMap(e -> e.getValue().unpack(e.getKey())); + } + ++ // Paper start - Perf: Remove streams from hot code ++ private List decompress() { ++ final List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ for (final Map.Entry entry : this.gossips.entrySet()) { ++ for (final GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) { ++ if (cur.weightedValue() != 0) { ++ list.add(cur); ++ } ++ } ++ } ++ return list; ++ } ++ // Paper end - Perf: Remove streams from hot code ++ + private Collection selectGossipsForTransfer(final RandomSource random, final int maxCount) { +- List entries = this.unpack().toList(); ++ List entries = this.decompress(); // Paper - Perf: Remove streams from hot code + if (entries.isEmpty()) { + return Collections.emptyList(); + } else { +@@ -176,7 +190,23 @@ public class GossipContainer { + private final Object2IntMap entries = new Object2IntOpenHashMap<>(); + + public int weightedValue(final Predicate types) { +- return this.entries.object2IntEntrySet().stream().filter(e -> types.test(e.getKey())).mapToInt(e -> e.getIntValue() * e.getKey().weight).sum(); ++ // Paper start - Perf: Remove streams from hot code ++ int weight = 0; ++ for (Object2IntMap.Entry entry : entries.object2IntEntrySet()) { ++ if (types.test(entry.getKey())) { ++ weight += entry.getIntValue() * entry.getKey().weight; ++ } ++ } ++ return weight; ++ } ++ ++ public List decompress(final UUID uuid) { ++ List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); ++ for (Object2IntMap.Entry entry : entries.object2IntEntrySet()) { ++ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue())); ++ } ++ return list; ++ // Paper end - Perf: Remove streams from hot code + } + + public Stream unpack(final UUID target) { +diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java +index e08da5b08dca5849fe0fd6d0ed237fbd36881e15..8aeea55380462421cde43afb4b2fb0ce44b65195 100644 +--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java +@@ -24,13 +24,17 @@ public class NearestItemSensor extends Sensor { + @Override + protected void doTick(final ServerLevel level, final Mob body) { + Brain brain = body.getBrain(); +- List items = level.getEntitiesOfClass(ItemEntity.class, body.getBoundingBox().inflate(32.0, 16.0, 32.0), item -> true); ++ List items = level.getEntitiesOfClass(ItemEntity.class, body.getBoundingBox().inflate(32.0, 16.0, 32.0), item -> item.closerThan(body, MAX_DISTANCE_TO_WANTED_ITEM) && body.wantsToPickUp(level, item.getItem())); // Paper - Perf: Move predicate into getEntities + items.sort(Comparator.comparingDouble(body::distanceToSqr)); +- Optional nearestVisibleLovedItem = items.stream() +- .filter(itemEntity -> body.wantsToPickUp(level, itemEntity.getItem())) +- .filter(itemEntity -> itemEntity.closerThan(body, 32.0)) +- .filter(body::hasLineOfSight) +- .findFirst(); +- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, nearestVisibleLovedItem); ++ // Paper start - Perf: remove streams from hot code ++ ItemEntity nearest = null; ++ for (final ItemEntity item : items) { ++ if (body.hasLineOfSight(item)) { // Paper - Perf: Move predicate into getEntities ++ nearest = item; ++ break; ++ } ++ } ++ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest)); ++ // Paper end - Perf: remove streams from hot code + } + } diff --git a/paper-server/patches/features/0010-optimize-dirt-and-snow-spreading.patch b/paper-server/patches/features/0010-optimize-dirt-and-snow-spreading.patch deleted file mode 100644 index 91b9978c2fea..000000000000 --- a/paper-server/patches/features/0010-optimize-dirt-and-snow-spreading.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: lukas81298 -Date: Fri, 22 Jan 2021 21:50:18 +0100 -Subject: [PATCH] optimize dirt and snow spreading - - -diff --git a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -index 0036d684e619e373b0e15e0c38788a2231864b52..b11c6d76cb9df1f92a4581646929d0dc79ec3e4a 100644 ---- a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -+++ b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -@@ -17,8 +17,13 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock { - } - - private static boolean canBeGrass(BlockState state, LevelReader level, BlockPos pos) { -+ // Paper start - Perf: optimize dirt and snow spreading -+ return canBeGrass(level.getChunk(pos), state, level, pos); -+ } -+ private static boolean canBeGrass(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader level, BlockPos pos) { -+ // Paper end - Perf: optimize dirt and snow spreading - BlockPos blockPos = pos.above(); -- BlockState blockState = level.getBlockState(blockPos); -+ BlockState blockState = chunk.getBlockState(blockPos); // Paper - Perf: optimize dirt and snow spreading - if (blockState.is(Blocks.SNOW) && blockState.getValue(SnowLayerBlock.LAYERS) == 1) { - return true; - } else if (blockState.getFluidState().getAmount() == 8) { -@@ -33,14 +38,27 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock { - protected abstract MapCodec codec(); - - private static boolean canPropagate(BlockState state, LevelReader level, BlockPos pos) { -+ // Paper start - Perf: optimize dirt and snow spreading -+ return canPropagate(level.getChunk(pos), state, level, pos); -+ } -+ -+ private static boolean canPropagate(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader level, BlockPos pos) { -+ // Paper end - Perf: optimize dirt and snow spreading - BlockPos blockPos = pos.above(); -- return canBeGrass(state, level, pos) && !level.getFluidState(blockPos).is(FluidTags.WATER); -+ return canBeGrass(chunk, state, level, pos) && !chunk.getFluidState(blockPos).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading - } - - @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks -- if (!canBeGrass(state, level, pos)) { -+ // Paper start - Perf: optimize dirt and snow spreading -+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = level.getChunkIfLoaded(pos); -+ if (cachedBlockChunk == null) { // Is this needed? -+ return; -+ } -+ -+ if (!canBeGrass(cachedBlockChunk, state, level, pos)) { -+ // Paper end - Perf: optimize dirt and snow spreading - // CraftBukkit start - if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) { - return; -@@ -53,8 +71,20 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock { - - for (int i = 0; i < 4; i++) { - BlockPos blockPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); -- if (level.getBlockState(blockPos).is(Blocks.DIRT) && canPropagate(blockState, level, blockPos)) { -- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState.setValue(SNOWY, isSnowySetting(level.getBlockState(blockPos.above()))), Block.UPDATE_ALL); // CraftBukkit -+ // Paper start - Perf: optimize dirt and snow spreading -+ if (pos.getX() == blockPos.getX() && pos.getY() == blockPos.getY() && pos.getZ() == blockPos.getZ()) { -+ continue; -+ } -+ -+ final net.minecraft.world.level.chunk.ChunkAccess access; -+ if (cachedBlockChunk.locX == blockPos.getX() >> 4 && cachedBlockChunk.locZ == blockPos.getZ() >> 4) { -+ access = cachedBlockChunk; -+ } else { -+ access = level.getChunkAt(blockPos); -+ } -+ if (access.getBlockState(blockPos).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(access, blockState, level, blockPos)) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState.setValue(SNOWY, isSnowySetting(access.getBlockState(blockPos.above()))), Block.UPDATE_ALL); // CraftBukkit -+ // Paper end - Perf: optimize dirt and snow spreading - } - } - } diff --git a/paper-server/patches/features/0011-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/paper-server/patches/features/0011-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch new file mode 100644 index 000000000000..b1512ccfe900 --- /dev/null +++ b/paper-server/patches/features/0011-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 4 Aug 2020 22:24:15 +0200 +Subject: [PATCH] Optimize Pathfinder - Remove Streams / Optimized collections + +I utilized the IDE to convert streams to non streams code, so shouldn't +be any risk of behavior change. Only did minor optimization of the +generated code set to remove unnecessary things. + +I expect us to just drop this patch on next major update and re-apply +it with the IDE again and re-apply the collections optimization. + +Optimize collection by creating a list instead of a set of the key and value. + +This lets us get faster foreach iteration, as well as avoids map lookups on +the values when needed. + +diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java +index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e7308620653774 100644 +--- a/net/minecraft/world/level/pathfinder/PathFinder.java ++++ b/net/minecraft/world/level/pathfinder/PathFinder.java +@@ -54,8 +54,12 @@ public class PathFinder { + if (from == null) { + return null; + } else { +- Map tos = targets.stream() +- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity())); ++ // Paper start - Perf: remove streams and optimize collection ++ List> tos = Lists.newArrayList(); ++ for (BlockPos pos : targets) { ++ tos.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); ++ } ++ // Paper end - Perf: remove streams and optimize collection + Path path = this.findPath(from, tos, maxPathLength, reachRange, maxVisitedNodesMultiplier); + this.nodeEvaluator.done(); + return path; +@@ -63,12 +67,12 @@ public class PathFinder { + } + + private @Nullable Path findPath( +- final Node from, final Map targetMap, final float maxPathLength, final int reachRange, final float maxVisitedNodesMultiplier ++ final Node from, final List> targets, final float maxPathLength, final int reachRange, final float maxVisitedNodesMultiplier // Paper - optimize collection + ) { + ProfilerFiller profiler = Profiler.get(); + profiler.push("find_path"); + profiler.markForCharting(MetricCategory.PATH_FINDING); +- Set targets = targetMap.keySet(); ++ //Set targets = targetMap.keySet(); // Paper - unused + from.g = 0.0F; + from.h = this.getBestH(from, targets); + from.f = from.h; +@@ -77,7 +81,7 @@ public class PathFinder { + boolean captureDebug = this.captureDebug.getAsBoolean(); + Set closedSet = captureDebug ? new HashSet<>() : Set.of(); + int count = 0; +- Set reachedTargets = Sets.newHashSetWithExpectedSize(targets.size()); ++ List> reachedTargets = Lists.newArrayListWithExpectedSize(targets.size()); // Paper - optimize collection + int maxVisitedNodesAdjusted = (int)(this.maxVisitedNodes * maxVisitedNodesMultiplier); + + while (!this.openSet.isEmpty()) { +@@ -88,10 +92,14 @@ public class PathFinder { + Node current = this.openSet.pop(); + current.closed = true; + +- for (Target target : targets) { ++ // Paper start - optimize collection ++ for (int positionIndex = 0, size = targets.size(); positionIndex < size; positionIndex++) { ++ final Map.Entry entry = targets.get(positionIndex); ++ Target target = entry.getKey(); + if (current.distanceManhattan(target) <= reachRange) { + target.setReached(); +- reachedTargets.add(target); ++ reachedTargets.add(entry); ++ // Paper end - Perf: remove streams and optimize collection + } + } + +@@ -126,34 +134,40 @@ public class PathFinder { + } + } + +- Optional optPath = !reachedTargets.isEmpty() +- ? reachedTargets.stream() +- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), true)) +- .min(Comparator.comparingInt(Path::getNodeCount)) +- : targets.stream() +- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), false)) +- .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount)); ++ Path best = null; ++ boolean entryListIsEmpty = reachedTargets.isEmpty(); ++ Comparator comparator = entryListIsEmpty ++ ? Comparator.comparingInt(Path::getNodeCount) ++ : Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount); ++ for (Map.Entry entry : entryListIsEmpty ? targets : reachedTargets) { ++ Path path = this.reconstructPath(entry.getKey().getBestNode(), entry.getValue(), !entryListIsEmpty); ++ if (best == null || comparator.compare(path, best) < 0) { ++ best = path; ++ } ++ } + profiler.pop(); +- if (optPath.isEmpty()) { +- return null; +- } else { +- Path path = optPath.get(); +- if (captureDebug) { +- path.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), targets); ++ if (captureDebug && best != null) { ++ Set set = Sets.newHashSet(); ++ for(Map.Entry entry : targets) { ++ set.add(entry.getKey()); + } +- +- return path; ++ best.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), set); + } ++ return best; ++ // Paper end - Perf: remove streams and optimize collection + } + + protected float distance(final Node from, final Node to) { + return from.distanceTo(to); + } + +- private float getBestH(final Node from, final Set targets) { ++ private float getBestH(final Node from, final List> targets) { // Paper - Perf: remove streams and optimize collection; Set -> List> + float bestH = Float.MAX_VALUE; + +- for (Target target : targets) { ++ // Paper start - Perf: remove streams and optimize collection ++ for (int i = 0, targetsSize = targets.size(); i < targetsSize; i++) { ++ final Target target = targets.get(i).getKey(); ++ // Paper end - Perf: remove streams and optimize collection + float h = from.distanceTo(target); + target.updateBest(h, from); + bestH = Math.min(h, bestH); diff --git a/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch b/paper-server/patches/features/0012-Fix-entity-tracker-desync-when-new-players-are-added.patch similarity index 79% rename from paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch rename to paper-server/patches/features/0012-Fix-entity-tracker-desync-when-new-players-are-added.patch index 10cb5e053233..d73cf7f72af1 100644 --- a/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch +++ b/paper-server/patches/features/0012-Fix-entity-tracker-desync-when-new-players-are-added.patch @@ -29,7 +29,7 @@ client will not tick the entity and thus not lerp the entity from its old position to its new position. diff --git a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java -index 2a86ca1de6920017be6cd4a3a5251e892067f07c..f571ff64ae1007f8f0632febd2dcca7056a29b3c 100644 +index cff05f64af7f425b77cbbd7680c5cc592faa798c..0ab4080c8e30d5ee14ce5fcbac64b0316ea6a949 100644 --- a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java +++ b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java @@ -38,9 +38,11 @@ public class ClientboundAddEntityPacket implements Packet passengers = this.entity.getPassengers(); +@@ -126,7 +133,7 @@ public class ServerEntity { this.sendDirtyEntityData(); } - if (this.tickCount % this.updateInterval == 0 || this.entity.needsSync || this.entity.getEntityData().isDirty()) { + if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.needsSync || this.entity.getEntityData().isDirty()) { // Paper - fix desync when a player is added to the tracker - byte b = Mth.packDegrees(this.entity.getYRot()); - byte b1 = Mth.packDegrees(this.entity.getXRot()); - boolean flag = Math.abs(b - this.lastSentYRot) >= 1 || Math.abs(b1 - this.lastSentXRot) >= 1; -@@ -164,7 +171,7 @@ public class ServerEntity { - long l1 = this.positionCodec.encodeY(vec3); - long l2 = this.positionCodec.encodeZ(vec3); - boolean flag5 = l < -32768L || l > 32767L || l1 < -32768L || l1 > 32767L || l2 < -32768L || l2 > 32767L; + byte yRotn = Mth.packDegrees(this.entity.getYRot()); + byte xRotn = Mth.packDegrees(this.entity.getXRot()); + boolean shouldSendRotation = Math.abs(yRotn - this.lastSentYRot) >= 1 || Math.abs(xRotn - this.lastSentXRot) >= 1; +@@ -160,7 +167,7 @@ public class ServerEntity { + long ya = this.positionCodec.encodeY(currentPosition); + long za = this.positionCodec.encodeZ(currentPosition); + boolean deltaTooBig = xa < -32768L || xa > 32767L || ya < -32768L || ya > 32767L || za < -32768L || za > 32767L; - if (this.entity.getRequiresPrecisePosition() + if (this.forceStateResync || this.entity.getRequiresPrecisePosition() // Paper - fix desync when a player is added to the tracker - || flag5 + || deltaTooBig || this.teleportDelay > 400 || this.wasRiding -@@ -233,6 +240,7 @@ public class ServerEntity { +@@ -229,6 +236,7 @@ public class ServerEntity { } this.entity.needsSync = false; diff --git a/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch b/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch deleted file mode 100644 index 6ada9c1dfda3..000000000000 --- a/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Josh Roy <10731363+JRoy@users.noreply.github.com> -Date: Wed, 1 Jul 2020 18:01:49 -0400 -Subject: [PATCH] Remove streams from hot code - -Co-authored-by: Bjarne Koll -Co-authored-by: Spottedleaf - -diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java -index c215d97c24e6501e1a48a76fc08bf48ff4dfe462..bd31d1cac0d022a72bd536c41d1ef811886e7068 100644 ---- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java -+++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java -@@ -57,7 +57,7 @@ public class GateBehavior implements BehaviorControl - if (this.hasRequiredMemories(entity)) { - this.status = Behavior.Status.RUNNING; - this.orderPolicy.apply(this.behaviors); -- this.runningPolicy.apply(this.behaviors.stream(), level, entity, gameTime); -+ this.runningPolicy.apply(this.behaviors, level, entity, gameTime); // Paper - Perf: Remove streams from hot code - return true; - } else { - return false; -@@ -66,10 +66,13 @@ public class GateBehavior implements BehaviorControl - - @Override - public final void tickOrStop(ServerLevel level, E entity, long gameTime) { -- this.behaviors -- .stream() -- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING) -- .forEach(behavior -> behavior.tickOrStop(level, entity, gameTime)); -+ // Paper start - Perf: Remove streams from hot code -+ for (final BehaviorControl behavior : this.behaviors) { -+ if (behavior.getStatus() == Behavior.Status.RUNNING) { -+ behavior.tickOrStop(level, entity, gameTime); -+ } -+ } -+ // Paper end - Perf: Remove streams from hot code - if (this.behaviors.stream().noneMatch(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)) { - this.doStop(level, entity, gameTime); - } -@@ -78,11 +81,16 @@ public class GateBehavior implements BehaviorControl - @Override - public final void doStop(ServerLevel level, E entity, long gameTime) { - this.status = Behavior.Status.STOPPED; -- this.behaviors -- .stream() -- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING) -- .forEach(behavior -> behavior.doStop(level, entity, gameTime)); -- this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory); -+ // Paper start - Perf: Remove streams from hot code -+ for (final BehaviorControl behavior : this.behaviors) { -+ if (behavior.getStatus() == Behavior.Status.RUNNING) { -+ behavior.doStop(level, entity, gameTime); -+ } -+ } -+ for (final MemoryModuleType exitErasedMemory : this.exitErasedMemories) { -+ entity.getBrain().eraseMemory(exitErasedMemory); -+ } -+ // Paper end - Perf: Remove streams from hot code - } - - @Override -@@ -116,20 +124,30 @@ public class GateBehavior implements BehaviorControl - - public static enum RunningPolicy { - RUN_ONE { -+ // Paper start - Perf: Remove streams from hot code - @Override -- public void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime) { -- behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED) -- .filter(behavior -> behavior.tryStart(level, owner, gameTime)) -- .findFirst(); -+ public void apply(ShufflingList> behaviors, ServerLevel level, E owner, long gameTime) { -+ for (final BehaviorControl behavior : behaviors) { -+ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(level, owner, gameTime)) { -+ break; -+ } -+ } -+ // Paper end - Perf: Remove streams from hot code - } - }, - TRY_ALL { -+ // Paper start - Perf: Remove streams from hot code - @Override -- public void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime) { -- behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED).forEach(behavior -> behavior.tryStart(level, owner, gameTime)); -+ public void apply(ShufflingList> behaviors, ServerLevel level, E owner, long gameTime) { -+ for (final BehaviorControl behavior : behaviors) { -+ if (behavior.getStatus() == Behavior.Status.STOPPED) { -+ behavior.tryStart(level, owner, gameTime); -+ } -+ } -+ // Paper end - Perf: Remove streams from hot code - } - }; - -- public abstract void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime); -+ public abstract void apply(ShufflingList> behaviors, ServerLevel level, E owner, long gameTime); // Paper - Perf: Remove streams from hot code - } - } -diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java -index d93ef8d7ff04ffd3d7434ea6e2d476115203215b..425ca1931fb0a5c33ba7aaf4f639409c9fea836f 100644 ---- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java -+++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java -@@ -28,7 +28,7 @@ import net.minecraft.util.VisibleForDebug; - public class GossipContainer { - public static final Codec CODEC = GossipContainer.GossipEntry.CODEC - .listOf() -- .xmap(GossipContainer::new, gossipContainer -> gossipContainer.unpack().toList()); -+ .xmap(GossipContainer::new, gossipContainer -> gossipContainer.decompress()); // Paper - Perf: Remove streams from hot code - public static final int DISCARD_THRESHOLD = 2; - public final Map gossips = new HashMap<>(); - -@@ -65,8 +65,22 @@ public class GossipContainer { - return this.gossips.entrySet().stream().flatMap(entry -> entry.getValue().unpack(entry.getKey())); - } - -+ // Paper start - Perf: Remove streams from hot code -+ private List decompress() { -+ final List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ for (final Map.Entry entry : this.gossips.entrySet()) { -+ for (final GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) { -+ if (cur.weightedValue() != 0) { -+ list.add(cur); -+ } -+ } -+ } -+ return list; -+ } -+ // Paper end - Perf: Remove streams from hot code -+ - private Collection selectGossipsForTransfer(RandomSource random, int amount) { -- List list = this.unpack().toList(); -+ List list = this.decompress(); // Paper - Perf: Remove streams from hot code - if (list.isEmpty()) { - return Collections.emptyList(); - } else { -@@ -176,12 +190,23 @@ public class GossipContainer { - final Object2IntMap entries = new Object2IntOpenHashMap<>(); - - public int weightedValue(Predicate gossipType) { -- return this.entries -- .object2IntEntrySet() -- .stream() -- .filter(gossip -> gossipType.test(gossip.getKey())) -- .mapToInt(gossip -> gossip.getIntValue() * gossip.getKey().weight) -- .sum(); -+ // Paper start - Perf: Remove streams from hot code -+ int weight = 0; -+ for (Object2IntMap.Entry entry : entries.object2IntEntrySet()) { -+ if (gossipType.test(entry.getKey())) { -+ weight += entry.getIntValue() * entry.getKey().weight; -+ } -+ } -+ return weight; -+ } -+ -+ public List decompress(UUID uuid) { -+ List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ for (Object2IntMap.Entry entry : entries.object2IntEntrySet()) { -+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue())); -+ } -+ return list; -+ // Paper end - Perf: Remove streams from hot code - } - - public Stream unpack(UUID identifier) { -diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -index 38873e56e95dc772b184e4271f7af1fb411ac9f8..09fd13e2d958da8326276c4dadf25bf488aff5ac 100644 ---- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java -@@ -24,13 +24,17 @@ public class NearestItemSensor extends Sensor { - @Override - protected void doTick(ServerLevel level, Mob entity) { - Brain brain = entity.getBrain(); -- List entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true); -+ List entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities - entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr)); -- Optional optional = entitiesOfClass.stream() -- .filter(itemEntity -> entity.wantsToPickUp(level, itemEntity.getItem())) -- .filter(itemEntity -> itemEntity.closerThan(entity, 32.0)) -- .filter(entity::hasLineOfSight) -- .findFirst(); -- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional); -+ // Paper start - Perf: remove streams from hot code -+ ItemEntity nearest = null; -+ for (final ItemEntity itemEntity : entitiesOfClass) { -+ if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities -+ nearest = itemEntity; -+ break; -+ } -+ } -+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest)); -+ // Paper end - Perf: remove streams from hot code - } - } diff --git a/paper-server/patches/features/0015-Eigencraft-redstone-implementation.patch b/paper-server/patches/features/0013-Eigencraft-redstone-implementation.patch similarity index 97% rename from paper-server/patches/features/0015-Eigencraft-redstone-implementation.patch rename to paper-server/patches/features/0013-Eigencraft-redstone-implementation.patch index ef84f13c5404..7ec3b042d881 100644 --- a/paper-server/patches/features/0015-Eigencraft-redstone-implementation.patch +++ b/paper-server/patches/features/0013-Eigencraft-redstone-implementation.patch @@ -978,11 +978,11 @@ index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd + } +} diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java -index 417e12d3dfabdfce40d6a53d217b86a39defc553..d7ff98f4ecadd37f22d0a38d94a5975db60d6285 100644 +index 4df1650706244b21039a5daeb8bdf8bee59da1db..264fde5f1021f7a313f37aa6a965ba89e357b599 100644 --- a/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/net/minecraft/world/level/block/RedStoneWireBlock.java -@@ -264,6 +264,60 @@ public class RedStoneWireBlock extends Block { - return state.isFaceSturdy(level, pos, Direction.UP) || state.is(Blocks.HOPPER); +@@ -268,6 +268,60 @@ public class RedStoneWireBlock extends Block { + return relativeState.isFaceSturdy(level, relativePos, Direction.UP) || relativeState.is(Blocks.HOPPER); } + // Paper start - Optimize redstone @@ -1039,19 +1039,19 @@ index 417e12d3dfabdfce40d6a53d217b86a39defc553..d7ff98f4ecadd37f22d0a38d94a5975d + } + // Paper end + - private void updatePowerStrength(Level level, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean updateShape) { - if (useExperimentalEvaluator(level)) { - new ExperimentalRedstoneWireEvaluator(this).updatePowerStrength(level, pos, state, orientation, updateShape); -@@ -292,7 +346,7 @@ public class RedStoneWireBlock extends Block { + private void updatePowerStrength( + final Level level, + final BlockPos pos, +@@ -302,7 +356,7 @@ public class RedStoneWireBlock extends Block { @Override - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { if (!oldState.is(state.getBlock()) && !level.isClientSide()) { - this.updatePowerStrength(level, pos, state, null, true); + this.updateSurroundingRedstone(level, pos, state, null, true); // Paper - Optimize redstone for (Direction direction : Direction.Plane.VERTICAL) { level.updateNeighborsAt(pos.relative(direction), this); -@@ -309,7 +363,7 @@ public class RedStoneWireBlock extends Block { +@@ -319,7 +373,7 @@ public class RedStoneWireBlock extends Block { level.updateNeighborsAt(pos.relative(direction), this); } @@ -1060,9 +1060,9 @@ index 417e12d3dfabdfce40d6a53d217b86a39defc553..d7ff98f4ecadd37f22d0a38d94a5975d this.updateNeighborsOfNeighboringWires(level, pos); } } -@@ -334,7 +388,7 @@ public class RedStoneWireBlock extends Block { +@@ -346,7 +400,7 @@ public class RedStoneWireBlock extends Block { if (!level.isClientSide()) { - if (neighborBlock != this || !useExperimentalEvaluator(level)) { + if (block != this || !useExperimentalEvaluator(level)) { if (state.canSurvive(level, pos)) { - this.updatePowerStrength(level, pos, state, orientation, false); + this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone @@ -1070,15 +1070,15 @@ index 417e12d3dfabdfce40d6a53d217b86a39defc553..d7ff98f4ecadd37f22d0a38d94a5975d dropResources(state, level, pos); level.removeBlock(pos, false); diff --git a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java -index 82a45a598cd3d7520b15bac9b47117ef7b1f98ba..53b8df8e6dd379126af3e1feb2220e222430ce94 100644 +index 8b0e25305f0666f1c44e29493258d010b1f73134..6e5b8af1f69e44484dcb9aab6a9f7b6b6b60e917 100644 --- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java +++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java -@@ -45,7 +45,7 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator { +@@ -47,7 +47,7 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator { } } -- private int calculateTargetStrength(Level level, BlockPos pos) { -+ public int calculateTargetStrength(Level level, BlockPos pos) { // Paper - Optimize redstone +- private int calculateTargetStrength(final Level level, final BlockPos pos) { ++ public int calculateTargetStrength(final Level level, final BlockPos pos) { // Paper - Optimize redstone int blockSignal = this.getBlockSignal(level, pos); return blockSignal == 15 ? blockSignal : Math.max(blockSignal, this.getIncomingWireSignal(level, pos)); } diff --git a/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch deleted file mode 100644 index ca4e5337cdbf..000000000000 --- a/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch +++ /dev/null @@ -1,150 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 4 Aug 2020 22:24:15 +0200 -Subject: [PATCH] Optimize Pathfinder - Remove Streams / Optimized collections - -I utilized the IDE to convert streams to non streams code, so shouldn't -be any risk of behavior change. Only did minor optimization of the -generated code set to remove unnecessary things. - -I expect us to just drop this patch on next major update and re-apply -it with the IDE again and re-apply the collections optimization. - -Optimize collection by creating a list instead of a set of the key and value. - -This lets us get faster foreach iteration, as well as avoids map lookups on -the values when needed. - -diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java -index d1cd00f0842f6fba1fa188de59bf111a4235bf8a..168b475b38b2872b27c1ab15f6846323ac16dd2c 100644 ---- a/net/minecraft/world/level/pathfinder/PathFinder.java -+++ b/net/minecraft/world/level/pathfinder/PathFinder.java -@@ -47,28 +47,32 @@ public class PathFinder { - if (start == null) { - return null; - } else { -- Map map = targets.stream() -- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity())); -+ // Paper start - Perf: remove streams and optimize collection -+ List> map = Lists.newArrayList(); -+ for (BlockPos pos : targets) { -+ map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); -+ } -+ // Paper end - Perf: remove streams and optimize collection - Path path = this.findPath(start, map, maxRange, reachRange, maxVisitedNodesMultiplier); - this.nodeEvaluator.done(); - return path; - } - } - -- private @Nullable Path findPath(Node node, Map targets, float maxRange, int reachRange, float maxVisitedNodesMultiplier) { -+ private @Nullable Path findPath(Node node, List> positions, float maxRange, int reachRange, float maxVisitedNodesMultiplier) { // Paper - optimize collection - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("find_path"); - profilerFiller.markForCharting(MetricCategory.PATH_FINDING); -- Set set = targets.keySet(); -+ // Set set = targetPositions.keySet(); // Paper - unused - node.g = 0.0F; -- node.h = this.getBestH(node, set); -+ node.h = this.getBestH(node, positions); // Paper - optimize collection - node.f = node.h; - this.openSet.clear(); - this.openSet.insert(node); - boolean asBoolean = this.captureDebug.getAsBoolean(); - Set set1 = asBoolean ? new HashSet<>() : Set.of(); - int i = 0; -- Set set2 = Sets.newHashSetWithExpectedSize(set.size()); -+ List> entryList = Lists.newArrayListWithExpectedSize(positions.size()); // Paper - optimize collection - int i1 = (int)(this.maxVisitedNodes * maxVisitedNodesMultiplier); - - while (!this.openSet.isEmpty()) { -@@ -79,14 +83,18 @@ public class PathFinder { - Node node1 = this.openSet.pop(); - node1.closed = true; - -- for (Target target : set) { -+ // Paper start - optimize collection -+ for (int positionIndex = 0, size = positions.size(); positionIndex < size; positionIndex++) { -+ final Map.Entry entry = positions.get(positionIndex); -+ Target target = entry.getKey(); - if (node1.distanceManhattan(target) <= reachRange) { - target.setReached(); -- set2.add(target); -+ entryList.add(entry); -+ // Paper end - Perf: remove streams and optimize collection - } - } - -- if (!set2.isEmpty()) { -+ if (!entryList.isEmpty()) { // Paper - Perf: remove streams and optimize collection; rename - break; - } - -@@ -105,7 +113,7 @@ public class PathFinder { - if (node2.walkedDistance < maxRange && (!node2.inOpenSet() || f1 < node2.g)) { - node2.cameFrom = node1; - node2.g = f1; -- node2.h = this.getBestH(node2, set) * 1.5F; -+ node2.h = this.getBestH(node2, positions) * 1.5F; // Paper - Perf: remove streams and optimize collection - if (node2.inOpenSet()) { - this.openSet.changeCost(node2, node2.g + node2.h); - } else { -@@ -117,34 +125,41 @@ public class PathFinder { - } - } - -- Optional optional = !set2.isEmpty() -- ? set2.stream() -- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targets.get(pathfinder), true)) -- .min(Comparator.comparingInt(Path::getNodeCount)) -- : set.stream() -- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targets.get(pathfinder), false)) -- .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount)); -+ // Paper start - Perf: remove streams and optimize collection -+ Path best = null; -+ boolean entryListIsEmpty = entryList.isEmpty(); -+ Comparator comparator = entryListIsEmpty -+ ? Comparator.comparingInt(Path::getNodeCount) -+ : Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount); -+ for (Map.Entry entry : entryListIsEmpty ? positions : entryList) { -+ Path path = this.reconstructPath(entry.getKey().getBestNode(), entry.getValue(), !entryListIsEmpty); -+ if (best == null || comparator.compare(path, best) < 0) { -+ best = path; -+ } -+ } - profilerFiller.pop(); -- if (optional.isEmpty()) { -- return null; -- } else { -- Path path = optional.get(); -- if (asBoolean) { -- path.setDebug(this.openSet.getHeap(), set1.toArray(Node[]::new), set); -+ if(asBoolean && best != null) { -+ Set set = Sets.newHashSet(); -+ for(Map.Entry entry : positions) { -+ set.add(entry.getKey()); - } -- -- return path; -+ best.setDebug(this.openSet.getHeap(), set1.toArray(Node[]::new), set); - } -+ return best; -+ // Paper end - Perf: remove streams and optimize collection - } - - protected float distance(Node first, Node second) { - return first.distanceTo(second); - } - -- private float getBestH(Node node, Set targets) { -+ private float getBestH(Node node, List> targets) { // Paper - Perf: remove streams and optimize collection; Set -> List> - float f = Float.MAX_VALUE; - -- for (Target target : targets) { -+ // Paper start - Perf: remove streams and optimize collection -+ for (int i = 0, targetsSize = targets.size(); i < targetsSize; i++) { -+ final Target target = targets.get(i).getKey(); -+ // Paper end - Perf: remove streams and optimize collection - float f1 = node.distanceTo(target); - target.updateBest(f1, node); - f = Math.min(f1, f); diff --git a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch b/paper-server/patches/features/0014-Add-Alternate-Current-redstone-implementation.patch similarity index 98% rename from paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch rename to paper-server/patches/features/0014-Add-Alternate-Current-redstone-implementation.patch index 68867b6dfbd7..8d4d7d313a09 100644 --- a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch +++ b/paper-server/patches/features/0014-Add-Alternate-Current-redstone-implementation.patch @@ -2326,18 +2326,18 @@ index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9 + } +} diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index bdbc15bfbbfeae2bc5b884e300b86cb25c88840f..ef7e24716c2fc6a643d107cadcf743f80b39af41 100644 +index 43c47bdd2fdb7731eec5301e20f923d0703a36fc..75068c07d1892882a85e27e30da8ac9906cf16e7 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -227,6 +227,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public final net.minecraft.server.level.progress.LevelLoadListener levelLoadListener; +@@ -232,6 +232,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet + public final net.minecraft.world.level.storage.LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings; public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent + private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) @Override public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { -@@ -2696,6 +2697,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2434,6 +2435,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet return this.debugSynchronizers; } @@ -2348,14 +2348,14 @@ index bdbc15bfbbfeae2bc5b884e300b86cb25c88840f..ef7e24716c2fc6a643d107cadcf743f8 + } + // Paper end - optimize redstone (Alternate Current) + - public boolean isAllowedToEnterPortal(Level level) { - return level.dimension() != Level.NETHER || this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS); + public boolean isAllowedToEnterPortal(final Level toLevel) { + return toLevel.dimension() != Level.NETHER || this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS); } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 9e88d83b31129cc853afe60d841838852a33fc45..935aacd607bb1960bc5f01b3fd025603edd1dbd6 100644 +index ad39c0822f757216d817934ba18440c228dc6be3..52e870443337adbd7a573cbc49a0b094a84a905d 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -2049,6 +2049,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1446,6 +1446,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return this.palettedContainerFactory; } @@ -2374,11 +2374,11 @@ index 9e88d83b31129cc853afe60d841838852a33fc45..935aacd607bb1960bc5f01b3fd025603 NONE("none"), BLOCK("block"), diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java -index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff5810d775c38 100644 +index 264fde5f1021f7a313f37aa6a965ba89e357b599..872a4895ad25293acaf7dee3aa2305ce18013d02 100644 --- a/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/net/minecraft/world/level/block/RedStoneWireBlock.java -@@ -264,7 +264,7 @@ public class RedStoneWireBlock extends Block { - return state.isFaceSturdy(level, pos, Direction.UP) || state.is(Blocks.HOPPER); +@@ -268,7 +268,7 @@ public class RedStoneWireBlock extends Block { + return relativeState.isFaceSturdy(level, relativePos, Direction.UP) || relativeState.is(Blocks.HOPPER); } - // Paper start - Optimize redstone @@ -2386,9 +2386,9 @@ index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff581 // The bulk of the new functionality is found in RedstoneWireTurbo.java io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this); -@@ -346,7 +346,13 @@ public class RedStoneWireBlock extends Block { +@@ -356,7 +356,13 @@ public class RedStoneWireBlock extends Block { @Override - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { if (!oldState.is(state.getBlock()) && !level.isClientSide()) { - this.updateSurroundingRedstone(level, pos, state, null, true); // Paper - Optimize redstone + // Paper start - optimize redstone - replace call to updatePowerStrength @@ -2401,7 +2401,7 @@ index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff581 for (Direction direction : Direction.Plane.VERTICAL) { level.updateNeighborsAt(pos.relative(direction), this); -@@ -363,7 +369,13 @@ public class RedStoneWireBlock extends Block { +@@ -373,7 +379,13 @@ public class RedStoneWireBlock extends Block { level.updateNeighborsAt(pos.relative(direction), this); } @@ -2416,9 +2416,9 @@ index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff581 this.updateNeighborsOfNeighboringWires(level, pos); } } -@@ -386,9 +398,15 @@ public class RedStoneWireBlock extends Block { - @Override - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +@@ -398,9 +410,15 @@ public class RedStoneWireBlock extends Block { + final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston + ) { if (!level.isClientSide()) { + // Paper start - optimize redstone (Alternate Current) + // Alternate Current handles breaking of redstone wires in the WireHandler. @@ -2426,7 +2426,7 @@ index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff581 + level.getWireHandler().onWireUpdated(pos, state, orientation); + } else + // Paper end - optimize redstone (Alternate Current) - if (neighborBlock != this || !useExperimentalEvaluator(level)) { + if (block != this || !useExperimentalEvaluator(level)) { if (state.canSurvive(level, pos)) { - this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone + this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone (Eigencraft) @@ -2434,7 +2434,7 @@ index d7ff98f4ecadd37f22d0a38d94a5975db60d6285..6d98bc37d88459d1e0a171b52bbff581 dropResources(state, level, pos); level.removeBlock(pos, false); diff --git a/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java b/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java -index 413d6b66a7e368ebb590064b0d0dd47b64c68659..05e99653bb1f3b392be86f9fa9814b87ca301bca 100644 +index aee5036475c11f9419fdc7cde3bd96633499ceb5..9e85806bddd2295c373003b2a56396fe0be078df 100644 --- a/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java +++ b/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java @@ -16,6 +16,11 @@ public class ExperimentalRedstoneUtils { diff --git a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch b/paper-server/patches/features_unapplied/0001-Moonrise-optimisation-patches.patch similarity index 100% rename from paper-server/patches/features/0001-Moonrise-optimisation-patches.patch rename to paper-server/patches/features_unapplied/0001-Moonrise-optimisation-patches.patch diff --git a/paper-server/patches/features/0002-Rewrite-dataconverter-system.patch b/paper-server/patches/features_unapplied/0002-Rewrite-dataconverter-system.patch similarity index 100% rename from paper-server/patches/features/0002-Rewrite-dataconverter-system.patch rename to paper-server/patches/features_unapplied/0002-Rewrite-dataconverter-system.patch diff --git a/paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/paper-server/patches/features_unapplied/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch similarity index 100% rename from paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch rename to paper-server/patches/features_unapplied/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch diff --git a/paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch b/paper-server/patches/features_unapplied/0018-Entity-load-save-limit-per-chunk.patch similarity index 100% rename from paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch rename to paper-server/patches/features_unapplied/0018-Entity-load-save-limit-per-chunk.patch diff --git a/paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/paper-server/patches/features_unapplied/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch similarity index 100% rename from paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch rename to paper-server/patches/features_unapplied/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch diff --git a/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch b/paper-server/patches/features_unapplied/0020-Incremental-chunk-and-player-saving.patch similarity index 100% rename from paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch rename to paper-server/patches/features_unapplied/0020-Incremental-chunk-and-player-saving.patch diff --git a/paper-server/patches/features/0021-Optimise-general-POI-access.patch b/paper-server/patches/features_unapplied/0021-Optimise-general-POI-access.patch similarity index 100% rename from paper-server/patches/features/0021-Optimise-general-POI-access.patch rename to paper-server/patches/features_unapplied/0021-Optimise-general-POI-access.patch diff --git a/paper-server/patches/features/0022-Flush-regionfiles-on-save-configuration-option.patch b/paper-server/patches/features_unapplied/0022-Flush-regionfiles-on-save-configuration-option.patch similarity index 100% rename from paper-server/patches/features/0022-Flush-regionfiles-on-save-configuration-option.patch rename to paper-server/patches/features_unapplied/0022-Flush-regionfiles-on-save-configuration-option.patch diff --git a/paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch b/paper-server/patches/features_unapplied/0023-Optimise-collision-checking-in-player-move-packet-ha.patch similarity index 100% rename from paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch rename to paper-server/patches/features_unapplied/0023-Optimise-collision-checking-in-player-move-packet-ha.patch diff --git a/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch b/paper-server/patches/features_unapplied/0024-Improve-keepalive-ping-system.patch similarity index 100% rename from paper-server/patches/features/0024-Improve-keepalive-ping-system.patch rename to paper-server/patches/features_unapplied/0024-Improve-keepalive-ping-system.patch diff --git a/paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch b/paper-server/patches/features_unapplied/0025-Optimise-EntityScheduler-ticking.patch similarity index 100% rename from paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch rename to paper-server/patches/features_unapplied/0025-Optimise-EntityScheduler-ticking.patch diff --git a/paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch b/paper-server/patches/features_unapplied/0026-Optional-per-player-mob-spawns.patch similarity index 100% rename from paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch rename to paper-server/patches/features_unapplied/0026-Optional-per-player-mob-spawns.patch diff --git a/paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/paper-server/patches/features_unapplied/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch similarity index 100% rename from paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch rename to paper-server/patches/features_unapplied/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch diff --git a/paper-server/patches/features/0028-Optimize-Hoppers.patch b/paper-server/patches/features_unapplied/0028-Optimize-Hoppers.patch similarity index 100% rename from paper-server/patches/features/0028-Optimize-Hoppers.patch rename to paper-server/patches/features_unapplied/0028-Optimize-Hoppers.patch diff --git a/paper-server/patches/features/0029-Anti-Xray.patch b/paper-server/patches/features_unapplied/0029-Anti-Xray.patch similarity index 100% rename from paper-server/patches/features/0029-Anti-Xray.patch rename to paper-server/patches/features_unapplied/0029-Anti-Xray.patch diff --git a/paper-server/patches/features/0030-Improve-exact-choice-recipe-ingredients.patch b/paper-server/patches/features_unapplied/0030-Improve-exact-choice-recipe-ingredients.patch similarity index 100% rename from paper-server/patches/features/0030-Improve-exact-choice-recipe-ingredients.patch rename to paper-server/patches/features_unapplied/0030-Improve-exact-choice-recipe-ingredients.patch diff --git a/paper-server/patches/features/0031-DataConverter-Fixes.patch b/paper-server/patches/features_unapplied/0031-DataConverter-Fixes.patch similarity index 100% rename from paper-server/patches/features/0031-DataConverter-Fixes.patch rename to paper-server/patches/features_unapplied/0031-DataConverter-Fixes.patch diff --git a/paper-server/patches/features/0032-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch b/paper-server/patches/features_unapplied/0032-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch similarity index 100% rename from paper-server/patches/features/0032-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch rename to paper-server/patches/features_unapplied/0032-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch diff --git a/paper-server/patches/rejected/net/minecraft/network/chat/ComponentUtils.java.patch b/paper-server/patches/rejected/net/minecraft/network/chat/ComponentUtils.java.patch new file mode 100644 index 000000000000..c257c714d0d5 --- /dev/null +++ b/paper-server/patches/rejected/net/minecraft/network/chat/ComponentUtils.java.patch @@ -0,0 +1,59 @@ +From 1297a393931168b81b895cb287186c8c5dd495d8 Mon Sep 17 00:00:00 2001 +From: File +Date: Sun, 20 Apr 1997 06:37:42 -0700 +Subject: [PATCH] paper File Patches + + +diff --git a/net/minecraft/network/chat/ComponentUtils.java b/net/minecraft/network/chat/ComponentUtils.java +index fafd6324eb133703a32c73331e94a47b601bf21a..fbd940cc73498b7bfa184ec17a749f1bd38dfb79 100644 +--- a/net/minecraft/network/chat/ComponentUtils.java ++++ b/net/minecraft/network/chat/ComponentUtils.java +@@ -49,18 +49,47 @@ public class ComponentUtils { + } + } + ++ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate. + public static Optional updateForEntity( + final @Nullable CommandSourceStack source, final Optional component, final @Nullable Entity entity, final int recursionDepth + ) throws CommandSyntaxException { + return component.isPresent() ? Optional.of(updateForEntity(source, component.get(), entity, recursionDepth)) : Optional.empty(); + } + ++ // Paper start - validate separator ++ public static Optional updateSeparatorForEntity(final @Nullable CommandSourceStack source, final Optional text, final @Nullable Entity sender, final int depth) throws CommandSyntaxException { ++ if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty(); ++ return Optional.of(updateForEntity(source, text.get(), sender, depth)); ++ } ++ ++ public static boolean isValidSelector(final Component component) { ++ final ComponentContents contents = component.getContents(); ++ ++ if (contents instanceof net.minecraft.network.chat.contents.NbtContents || contents instanceof net.minecraft.network.chat.contents.SelectorContents) ++ return false; ++ if (contents instanceof final net.minecraft.network.chat.contents.TranslatableContents translatableContents) { ++ for (final Object arg : translatableContents.getArgs()) { ++ if (arg instanceof final Component argumentAsComponent && !isValidSelector(argumentAsComponent)) ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - validate separator ++ + public static MutableComponent updateForEntity( +- final @Nullable CommandSourceStack source, final Component component, final @Nullable Entity entity, final int recursionDepth ++ final @Nullable CommandSourceStack source, Component component, final @Nullable Entity entity, final int recursionDepth // Paper - adventure; pass actual vanilla component + ) throws CommandSyntaxException { + if (recursionDepth > 100) { + return component.copy(); + } else { ++ // Paper start - adventure; pass actual vanilla component ++ if (component instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { ++ component = adventureComponent.deepConverted(); ++ } ++ // Paper end - adventure; pass actual vanilla component ++ + MutableComponent result = component.getContents().resolve(source, entity, recursionDepth + 1); + + for (Component sibling : component.getSiblings()) { diff --git a/paper-server/patches/rejected/net/minecraft/network/chat/contents/NbtContents.java.patch b/paper-server/patches/rejected/net/minecraft/network/chat/contents/NbtContents.java.patch new file mode 100644 index 000000000000..3f46bcf163d4 --- /dev/null +++ b/paper-server/patches/rejected/net/minecraft/network/chat/contents/NbtContents.java.patch @@ -0,0 +1,19 @@ +From 1297a393931168b81b895cb287186c8c5dd495d8 Mon Sep 17 00:00:00 2001 +From: File +Date: Sun, 20 Apr 1997 06:37:42 -0700 +Subject: [PATCH] paper File Patches + + +diff --git a/net/minecraft/network/chat/contents/NbtContents.java b/net/minecraft/network/chat/contents/NbtContents.java +index 042af4ff7254af09b3d969c3f35ca294b36ca5e1..5c79329d11cf646c97b36f7b187fa0b22fac4cb5 100644 +--- a/net/minecraft/network/chat/contents/NbtContents.java ++++ b/net/minecraft/network/chat/contents/NbtContents.java +@@ -70,7 +70,7 @@ public record NbtContents( + } + }); + Component resolvedSeparator = DataFixUtils.orElse( +- ComponentUtils.updateForEntity(source, this.separator, entity, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR ++ ComponentUtils.updateSeparatorForEntity(source, this.separator, entity, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator + ); + if (this.interpreting) { + RegistryOps registryOps = source.registryAccess().createSerializationContext(NbtOps.INSTANCE); diff --git a/paper-server/patches/rejected/net/minecraft/network/chat/contents/SelectorContents.java.patch b/paper-server/patches/rejected/net/minecraft/network/chat/contents/SelectorContents.java.patch new file mode 100644 index 000000000000..fce324ae41fc --- /dev/null +++ b/paper-server/patches/rejected/net/minecraft/network/chat/contents/SelectorContents.java.patch @@ -0,0 +1,19 @@ +From 1297a393931168b81b895cb287186c8c5dd495d8 Mon Sep 17 00:00:00 2001 +From: File +Date: Sun, 20 Apr 1997 06:37:42 -0700 +Subject: [PATCH] paper File Patches + + +diff --git a/net/minecraft/network/chat/contents/SelectorContents.java b/net/minecraft/network/chat/contents/SelectorContents.java +index 2dae94cfb703a78ee238f5766ad363de83d6c9c2..33fa16fbbc503d394ccb20feb65b0feed7967894 100644 +--- a/net/minecraft/network/chat/contents/SelectorContents.java ++++ b/net/minecraft/network/chat/contents/SelectorContents.java +@@ -36,7 +36,7 @@ public record SelectorContents(CompilableString selector, Option + if (source == null) { + return Component.empty(); + } else { +- Optional resolvedSeparator = ComponentUtils.updateForEntity(source, this.separator, entity, recursionDepth); ++ Optional resolvedSeparator = ComponentUtils.updateSeparatorForEntity(source, this.separator, entity, recursionDepth); // Paper - validate separator + return ComponentUtils.formatList(this.selector.compiled().findEntities(source), resolvedSeparator, Entity::getDisplayName); + } + } diff --git a/paper-server/patches/resources/data/minecraft/worldgen/noise_settings/caves.json.patch b/paper-server/patches/resources/data/minecraft/worldgen/noise_settings/caves.json.patch index 64ecd4557529..73fabf039b85 100644 --- a/paper-server/patches/resources/data/minecraft/worldgen/noise_settings/caves.json.patch +++ b/paper-server/patches/resources/data/minecraft/worldgen/noise_settings/caves.json.patch @@ -1,6 +1,6 @@ --- a/data/minecraft/worldgen/noise_settings/caves.json +++ b/data/minecraft/worldgen/noise_settings/caves.json -@@ -110,7 +_,8 @@ +@@ -94,7 +_,8 @@ "if_true": { "type": "minecraft:not", "invert": { @@ -10,7 +10,7 @@ "false_at_and_above": { "below_top": 0 }, -@@ -130,7 +_,8 @@ +@@ -114,7 +_,8 @@ { "type": "minecraft:condition", "if_true": { diff --git a/paper-server/patches/sources/com/mojang/brigadier/exceptions/CommandSyntaxException.java.patch b/paper-server/patches/sources/com/mojang/brigadier/exceptions/CommandSyntaxException.java.patch index 5a9ff8c8d0a8..8bbf644d9f1a 100644 --- a/paper-server/patches/sources/com/mojang/brigadier/exceptions/CommandSyntaxException.java.patch +++ b/paper-server/patches/sources/com/mojang/brigadier/exceptions/CommandSyntaxException.java.patch @@ -16,7 +16,7 @@ + + // Paper start - Brigadier API + @Override -+ public @org.jetbrains.annotations.Nullable net.kyori.adventure.text.Component componentMessage() { ++ public net.kyori.adventure.text.@org.jspecify.annotations.Nullable Component componentMessage() { + return io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(this.message); + } + // Paper end - Brigadier API diff --git a/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch b/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch index fa336bf0640a..590b8b09adbb 100644 --- a/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch +++ b/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch @@ -1,7 +1,7 @@ --- a/com/mojang/math/OctahedralGroup.java +++ b/com/mojang/math/OctahedralGroup.java -@@ -105,6 +_,12 @@ - .map(group -> Arrays.stream(values()).filter(octahedralGroup -> group.compose(octahedralGroup) == IDENTITY).findAny().get()) +@@ -99,6 +_,12 @@ + .map(f -> Arrays.stream(values()).filter(s -> f.compose(s) == IDENTITY).findAny().get()) .toArray(OctahedralGroup[]::new); + static { @@ -13,16 +13,16 @@ private OctahedralGroup(final String name, final SymmetricGroup3 permutation, final boolean invertX, final boolean invertY, final boolean invertZ) { this.name = name; this.invertX = invertX; -@@ -145,7 +_,7 @@ +@@ -139,7 +_,7 @@ return this.name; } -- public Direction rotate(Direction direction) { +- public Direction rotate(final Direction direction) { + public void initializeRotationDirections() { // Paper - Avoid Lazy Initialization for Enum Fields if (this.rotatedDirections == null) { - this.rotatedDirections = Util.makeEnumMap(Direction.class, direction1 -> { - Direction.Axis axis = direction1.getAxis(); -@@ -156,6 +_,11 @@ + this.rotatedDirections = Util.makeEnumMap(Direction.class, facing -> { + Direction.Axis oldAxis = facing.getAxis(); +@@ -150,6 +_,11 @@ }); } diff --git a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch index dd764f0757aa..90bde94658f9 100644 --- a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch +++ b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch @@ -63,7 +63,7 @@ + + public static Set getSentChunkKeys(final ServerPlayer player) { + final LongSet keys = new LongOpenHashSet(); -+ player.getChunkTrackingView().forEach(pos -> keys.add(pos.longKey)); ++ player.getChunkTrackingView().forEach(pos -> keys.add(pos.pack())); + return LongSets.unmodifiable(keys); + } + @@ -71,14 +71,14 @@ + final ObjectSet chunks = new ObjectOpenHashSet<>(); + final World world = player.level().getWorld(); + player.getChunkTrackingView().forEach(pos -> { -+ final org.bukkit.Chunk chunk = world.getChunkAt(pos.longKey); ++ final org.bukkit.Chunk chunk = world.getChunkAt(pos.pack()); + chunks.add(chunk); + }); + return ObjectSets.unmodifiable(chunks); + } + + public static boolean isChunkSent(final ServerPlayer player, final long chunkKey) { -+ return player.getChunkTrackingView().contains(new ChunkPos(chunkKey)); ++ return player.getChunkTrackingView().contains(ChunkPos.unpack(chunkKey)); + } + + public static boolean isSpiderCollidingWithWorldBorder(final Spider spider) { @@ -95,7 +95,7 @@ + world.getChunk(chunkX, chunkZ); // ensure full loaded + + net.minecraft.world.level.entity.PersistentEntitySectionManager entityManager = world.entityManager; -+ long pair = ChunkPos.asLong(chunkX, chunkZ); ++ long pair = ChunkPos.pack(chunkX, chunkZ); + + if (entityManager.areEntitiesLoaded(pair)) { + return entityManager.getEntities(new ChunkPos(chunkX, chunkZ)).stream() @@ -144,7 +144,7 @@ + public static java.util.Collection getPluginChunkTickets(net.minecraft.server.level.ServerLevel world, + int x, int z) { + net.minecraft.server.level.DistanceManager chunkDistanceManager = world.getChunkSource().chunkMap.distanceManager; -+ List tickets = chunkDistanceManager.ticketStorage.tickets.get(ChunkPos.asLong(x, z)); ++ List tickets = chunkDistanceManager.ticketStorage.tickets.get(ChunkPos.pack(x, z)); + + if (tickets == null) { + return java.util.Collections.emptyList(); diff --git a/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch b/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch index eb3d87a70583..5a2523953d3a 100644 --- a/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch +++ b/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/ChatFormatting.java +++ b/net/minecraft/ChatFormatting.java -@@ -114,6 +_,19 @@ - return friendlyName == null ? null : FORMATTING_BY_NAME.get(cleanName(friendlyName)); +@@ -112,6 +_,19 @@ + return name == null ? null : FORMATTING_BY_NAME.get(cleanName(name)); } + // Paper start - add method to get by hex value @@ -17,6 +17,6 @@ + } + // Paper end - add method to get by hex value + - public static @Nullable ChatFormatting getById(int index) { - if (index < 0) { + public static @Nullable ChatFormatting getById(final int id) { + if (id < 0) { return RESET; diff --git a/paper-server/patches/sources/net/minecraft/CrashReport.java.patch b/paper-server/patches/sources/net/minecraft/CrashReport.java.patch index da57e1a408d7..be129bb6bd26 100644 --- a/paper-server/patches/sources/net/minecraft/CrashReport.java.patch +++ b/paper-server/patches/sources/net/minecraft/CrashReport.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/CrashReport.java +++ b/net/minecraft/CrashReport.java @@ -34,6 +_,7 @@ - public CrashReport(String title, Throwable exception) { + public CrashReport(final String title, final Throwable t) { this.title = title; - this.exception = exception; + this.exception = t; + this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/advancements/AdvancementTree.java.patch b/paper-server/patches/sources/net/minecraft/advancements/AdvancementTree.java.patch index 6c17a3351155..5d37727fb21b 100644 --- a/paper-server/patches/sources/net/minecraft/advancements/AdvancementTree.java.patch +++ b/paper-server/patches/sources/net/minecraft/advancements/AdvancementTree.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/advancements/AdvancementTree.java +++ b/net/minecraft/advancements/AdvancementTree.java @@ -25,7 +_,7 @@ - this.remove(advancementNode); + this.remove(child); } - LOGGER.info("Forgot about advancement {}", node.holder()); @@ -17,4 +17,4 @@ + // LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload // Paper - Improve logging and errors; you say it was moved... but it wasn't :) it should be moved however, since this is called when the API creates an advancement } - private boolean tryInsert(AdvancementHolder advancement) { + private boolean tryInsert(final AdvancementHolder holder) { diff --git a/paper-server/patches/sources/net/minecraft/advancements/DisplayInfo.java.patch b/paper-server/patches/sources/net/minecraft/advancements/DisplayInfo.java.patch index c7956c2de5f2..c14505baa730 100644 --- a/paper-server/patches/sources/net/minecraft/advancements/DisplayInfo.java.patch +++ b/paper-server/patches/sources/net/minecraft/advancements/DisplayInfo.java.patch @@ -7,4 +7,4 @@ + public final io.papermc.paper.advancement.AdvancementDisplay paper = new io.papermc.paper.advancement.PaperAdvancementDisplay(this); // Paper - Add more advancement API public DisplayInfo( - ItemStack icon, + final ItemStackTemplate icon, diff --git a/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch b/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch index d559a186341d..1f1c3031b202 100644 --- a/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch +++ b/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/advancements/criterion/LocationPredicate.java +++ b/net/minecraft/advancements/criterion/LocationPredicate.java @@ -44,7 +_,7 @@ - public boolean matches(ServerLevel level, double x, double y, double z) { + public boolean matches(final ServerLevel level, final double x, final double y, final double z) { if (this.position.isPresent() && !this.position.get().matches(x, y, z)) { return false; - } else if (this.dimension.isPresent() && this.dimension.get() != level.dimension()) { + } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? level.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level))) { // Paper - Add option for strict advancement dimension checks return false; } else { - BlockPos blockPos = BlockPos.containing(x, y, z); + BlockPos pos = BlockPos.containing(x, y, z); diff --git a/paper-server/patches/sources/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java.patch b/paper-server/patches/sources/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java.patch index 8764e1c98d7a..a1e2ae309c8c 100644 --- a/paper-server/patches/sources/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java.patch +++ b/paper-server/patches/sources/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java.patch @@ -1,52 +1,52 @@ --- a/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java +++ b/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java -@@ -15,41 +_,41 @@ - import net.minecraft.world.level.storage.loot.LootContext; +@@ -17,41 +_,41 @@ + import net.minecraft.world.level.storage.loot.ValidationContextSource; public abstract class SimpleCriterionTrigger implements CriterionTrigger { - private final Map>> players = Maps.newIdentityHashMap(); + // private final Map>> players = Maps.newIdentityHashMap(); // Paper - fix PlayerAdvancements leak; moved into PlayerAdvancements to fix memory leak @Override - public final void addPlayerListener(PlayerAdvancements playerAdvancements, CriterionTrigger.Listener listener) { -- this.players.computeIfAbsent(playerAdvancements, advancements -> Sets.newHashSet()).add(listener); -+ playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(listener); // Paper - fix PlayerAdvancements leak + public final void addPlayerListener(final PlayerAdvancements player, final CriterionTrigger.Listener listener) { +- this.players.computeIfAbsent(player, k -> Sets.newHashSet()).add(listener); ++ player.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(listener); // Paper - fix PlayerAdvancements leak } @Override - public final void removePlayerListener(PlayerAdvancements playerAdvancements, CriterionTrigger.Listener listener) { -- Set> set = this.players.get(playerAdvancements); -+ Set> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak - if (set != null) { - set.remove(listener); - if (set.isEmpty()) { -- this.players.remove(playerAdvancements); -+ playerAdvancements.criterionData.remove(this); // Paper - fix PlayerAdvancements leak + public final void removePlayerListener(final PlayerAdvancements player, final CriterionTrigger.Listener listener) { +- Set> listeners = this.players.get(player); ++ Set> listeners = (Set) player.criterionData.get(this); // Paper - fix PlayerAdvancements leak + if (listeners != null) { + listeners.remove(listener); + if (listeners.isEmpty()) { +- this.players.remove(player); ++ player.criterionData.remove(this); // Paper - fix PlayerAdvancements leak } } } @Override - public final void removePlayerListeners(PlayerAdvancements playerAdvancements) { -- this.players.remove(playerAdvancements); -+ playerAdvancements.criterionData.remove(this); // Paper - fix PlayerAdvancements leak + public final void removePlayerListeners(final PlayerAdvancements player) { +- this.players.remove(player); ++ player.criterionData.remove(this); // Paper - fix PlayerAdvancements leak } - protected void trigger(ServerPlayer player, Predicate testTrigger) { + protected void trigger(final ServerPlayer player, final Predicate matcher) { PlayerAdvancements advancements = player.getAdvancements(); -- Set> set = this.players.get(advancements); -+ Set> set = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak - if (set != null && !set.isEmpty()) { -- LootContext lootContext = EntityPredicate.createContext(player, player); -+ LootContext lootContext = null; // EntityPredicate.createContext(player, player); // Paper - Perf: lazily create LootContext for criterions - List> list = null; +- Set> allListeners = this.players.get(advancements); ++ Set> allListeners = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak + if (allListeners != null && !allListeners.isEmpty()) { +- LootContext playerContext = EntityPredicate.createContext(player, player); ++ LootContext playerContext = null; // EntityPredicate.createContext(player, player); // Paper - Perf: lazily create LootContext for criterions + List> listeners = null; - for (CriterionTrigger.Listener listener : set) { - T simpleInstance = listener.trigger(); - if (testTrigger.test(simpleInstance)) { - Optional optional = simpleInstance.player(); -- if (optional.isEmpty() || optional.get().matches(lootContext)) { -+ if (optional.isEmpty() || optional.get().matches(lootContext = (lootContext == null ? EntityPredicate.createContext(player, player) : lootContext))) { // Paper - Perf: lazily create LootContext for criterions - if (list == null) { - list = Lists.newArrayList(); + for (CriterionTrigger.Listener listener : allListeners) { + T triggerInstance = listener.trigger(); + if (matcher.test(triggerInstance)) { + Optional predicate = triggerInstance.player(); +- if (predicate.isEmpty() || predicate.get().matches(playerContext)) { ++ if (predicate.isEmpty() || predicate.get().matches(playerContext = (playerContext == null ? EntityPredicate.createContext(player, player) : playerContext))) { // Paper - Perf: lazily create LootContext for criterions + if (listeners == null) { + listeners = Lists.newArrayList(); } diff --git a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch index 4266c14e397a..fc3e51faf2bf 100644 --- a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch @@ -4,8 +4,8 @@ import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; --public class CommandSourceStack implements ExecutionCommandSource, SharedSuggestionProvider { -+public class CommandSourceStack implements ExecutionCommandSource, SharedSuggestionProvider, io.papermc.paper.command.brigadier.PaperCommandSourceStack { // Paper - Brigadier API +-public class CommandSourceStack implements SharedSuggestionProvider, ExecutionCommandSource { ++public class CommandSourceStack implements SharedSuggestionProvider, ExecutionCommandSource, io.papermc.paper.command.brigadier.PaperCommandSourceStack { // Paper - Brigadier API public static final SimpleCommandExceptionType ERROR_NOT_PLAYER = new SimpleCommandExceptionType(Component.translatable("permissions.requires.player")); public static final SimpleCommandExceptionType ERROR_NOT_ENTITY = new SimpleCommandExceptionType(Component.translatable("permissions.requires.entity")); public final CommandSource source; @@ -16,7 +16,7 @@ + public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions public CommandSourceStack( - CommandSource source, + final CommandSource source, @@ -190,6 +_,30 @@ ); } @@ -45,7 +45,7 @@ + } + // Paper end - Expose 'with' functions from the CommandSourceStack + - public CommandSourceStack withRotation(Vec2 rotation) { + public CommandSourceStack withRotation(final Vec2 rotation) { return this.rotation.equals(rotation) ? this @@ -379,6 +_,32 @@ @@ -84,25 +84,25 @@ @@ -482,20 +_,25 @@ GameRules gameRules = this.level.getGameRules(); if (gameRules.get(GameRules.SEND_COMMAND_FEEDBACK)) { - for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) { -- if (serverPlayer.commandSource() != this.source && this.server.getPlayerList().isOp(serverPlayer.nameAndId())) { -+ if (serverPlayer.commandSource() != this.source && serverPlayer.getBukkitEntity().hasPermission("minecraft.admin.command_feedback")) { // CraftBukkit - serverPlayer.sendSystemMessage(component); + for (ServerPlayer player : this.server.getPlayerList().getPlayers()) { +- if (player.commandSource() != this.source && this.server.getPlayerList().isOp(player.nameAndId())) { ++ if (player.commandSource() != this.source && player.getBukkitEntity().hasPermission("minecraft.admin.command_feedback")) { // CraftBukkit + player.sendSystemMessage(broadcast); } } } - if (this.source != this.server && gameRules.get(GameRules.LOG_ADMIN_COMMANDS)) { + if (this.source != this.server && gameRules.get(GameRules.LOG_ADMIN_COMMANDS) && !org.spigotmc.SpigotConfig.silentCommandBlocks) { // Spigot - this.server.sendSystemMessage(component); + this.server.sendSystemMessage(broadcast); } } - public void sendFailure(Component message) { + public void sendFailure(final Component message) { + // Paper start - Add UnknownCommandEvent + this.sendFailure(message, true); + } -+ public void sendFailure(Component message, boolean withStyle) { ++ public void sendFailure(final Component message, final boolean withStyle) { + // Paper end - Add UnknownCommandEvent if (this.source.acceptsFailure() && !this.silent) { - this.source.sendSystemMessage(Component.empty().append(message).withStyle(ChatFormatting.RED)); @@ -119,7 +119,7 @@ } @Override -@@ -586,4 +_,16 @@ +@@ -584,4 +_,16 @@ public boolean isSilent() { return this.silent; } diff --git a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch index dfe4e32943b8..cfed6bb42dec 100644 --- a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/commands/Commands.java +++ b/net/minecraft/commands/Commands.java -@@ -155,6 +_,7 @@ +@@ -157,6 +_,7 @@ import org.slf4j.Logger; public class Commands { @@ -8,27 +8,27 @@ public static final String COMMAND_PREFIX = "/"; private static final ThreadLocal<@Nullable ExecutionContext> CURRENT_EXECUTION_CONTEXT = new ThreadLocal<>(); private static final Logger LOGGER = LogUtils.getLogger(); -@@ -179,6 +_,7 @@ +@@ -181,6 +_,7 @@ @Override - public boolean isRestricted(CommandNode node) { + public boolean isRestricted(final CommandNode node) { + if (node.getRequirement() instanceof RestrictedMarker) return true; // Paper - restricted api Predicate requirement = node.getRequirement(); return !requirement.test(this.noPermissionSource); } -@@ -186,6 +_,11 @@ +@@ -188,6 +_,11 @@ private final CommandDispatcher dispatcher = new CommandDispatcher<>(); - public Commands(Commands.CommandSelection selection, CommandBuildContext context) { + public Commands(final Commands.CommandSelection commandSelection, final CommandBuildContext context) { + // Paper start - Brigadier API - modern minecraft overloads that do not use redirects but are copies instead -+ this(selection, context, false); ++ this(commandSelection, context, false); + } -+ public Commands(Commands.CommandSelection selection, CommandBuildContext context, final boolean modern) { ++ public Commands(final Commands.CommandSelection commandSelection, final CommandBuildContext context, final boolean modern) { + // Paper end - Brigadier API - modern minecraft overloads that do not use redirects but are copies instead AdvancementCommands.register(this.dispatcher); AttributeCommand.register(this.dispatcher, context); ExecuteCommand.register(this.dispatcher, context); -@@ -296,6 +_,42 @@ +@@ -299,6 +_,42 @@ PublishCommand.register(this.dispatcher); } @@ -71,21 +71,21 @@ this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer()); } -@@ -315,6 +_,13 @@ +@@ -318,6 +_,13 @@ } - public void performCommand(ParseResults parseResults, String command) { + public void performCommand(final ParseResults command, final String commandString) { + // Paper start -+ this.performCommand(parseResults, command, false); ++ this.performCommand(command, commandString, false); + } + -+ public void performCommand(ParseResults parseResults, String command, boolean throwCommandError) { ++ public void performCommand(final ParseResults command, final String commandString, final boolean throwCommandError) { + org.spigotmc.AsyncCatcher.catchOp("Cannot perform command async"); + // Paper end - CommandSourceStack commandSourceStack = parseResults.getContext().getSource(); - Profiler.get().push(() -> "/" + command); - ContextChain contextChain = finishParsing(parseResults, command, commandSourceStack); -@@ -328,10 +_,13 @@ + CommandSourceStack sender = command.getContext().getSource(); + Profiler.get().push(() -> "/" + commandString); + ContextChain commandChain = finishParsing(command, commandString, sender); +@@ -331,10 +_,12 @@ ) ); } @@ -93,51 +93,50 @@ + // Paper start + } catch (Throwable var12) { // always gracefully handle it, no matter how bad:tm: + if (throwCommandError) throw var12; // rethrow directly if requested -+ // Paper end - MutableComponent mutableComponent = Component.literal(var12.getMessage() == null ? var12.getClass().getName() : var12.getMessage()); + MutableComponent hover = Component.literal(var12.getMessage() == null ? var12.getClass().getName() : var12.getMessage()); - if (LOGGER.isDebugEnabled()) { -- LOGGER.error("Command exception: /{}", command, var12); -+ LOGGER.error("Command exception: /{}", command, var12); // Paper - always show execution exception in console log -+ if (commandSourceStack.getServer().isDebugging() || LOGGER.isDebugEnabled()) { // Paper - Debugging +- LOGGER.error("Command exception: /{}", commandString, var12); ++ LOGGER.error("Command exception: /{}", commandString, var12); // Paper - always show execution exception in console log ++ if (sender.getServer().isDebugging() || LOGGER.isDebugEnabled()) { // Paper - Debugging StackTraceElement[] stackTrace = var12.getStackTrace(); for (int i = 0; i < Math.min(stackTrace.length, 3); i++) { -@@ -364,7 +_,11 @@ - return ContextChain.tryFlatten(parseResults.getContext().build(command)) - .orElseThrow(() -> CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parseResults.getReader())); +@@ -365,7 +_,11 @@ + return ContextChain.tryFlatten(command.getContext().build(commandString)) + .orElseThrow(() -> CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(command.getReader())); } catch (CommandSyntaxException var7) { -- source.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); +- sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); + // Paper start - Add UnknownCommandEvent + final net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text(); -+ // source.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); ++ // sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); + builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(var7.getRawMessage())); + // Paper end - Add UnknownCommandEvent if (var7.getInput() != null && var7.getCursor() >= 0) { - int min = Math.min(var7.getInput().length(), var7.getCursor()); - MutableComponent mutableComponent = Component.empty() -@@ -381,7 +_,17 @@ + int cursor = Math.min(var7.getInput().length(), var7.getCursor()); + MutableComponent context = Component.empty() +@@ -382,7 +_,17 @@ } - mutableComponent.append(Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC)); -- source.sendFailure(mutableComponent); + context.append(Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC)); +- sender.sendFailure(context); + // Paper start - Add UnknownCommandEvent -+ // source.sendFailure(mutableComponent); ++ // sender.sendFailure(context); + builder + .append(net.kyori.adventure.text.Component.newline()) -+ .append(io.papermc.paper.adventure.PaperAdventure.asAdventure(mutableComponent)); ++ .append(io.papermc.paper.adventure.PaperAdventure.asAdventure(context)); + } -+ org.bukkit.event.command.UnknownCommandEvent event = new org.bukkit.event.command.UnknownCommandEvent(source, command, org.spigotmc.SpigotConfig.unknownCommandMessage.isEmpty() ? null : builder.build()); ++ org.bukkit.event.command.UnknownCommandEvent event = new org.bukkit.event.command.UnknownCommandEvent(sender, commandString, org.spigotmc.SpigotConfig.unknownCommandMessage.isEmpty() ? null : builder.build()); + org.bukkit.Bukkit.getServer().getPluginManager().callEvent(event); + if (event.message() != null) { -+ source.sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); ++ sender.sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); + // Paper end - Add UnknownCommandEvent } return null; -@@ -409,17 +_,110 @@ +@@ -410,19 +_,112 @@ } - public void sendCommands(ServerPlayer player) { + public void sendCommands(final ServerPlayer player) { + // Paper start - Send empty commands if tab completion is disabled + if (org.spigotmc.SpigotConfig.tabComplete < 0) { + player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>(), COMMAND_NODE_INSPECTOR)); @@ -165,51 +164,53 @@ + + private void sendAsync(ServerPlayer player, java.util.Collection> dispatcherRootChildren) { + // Paper end - Perf: Async command map building - Map, CommandNode> map = new HashMap<>(); - RootCommandNode rootCommandNode = new RootCommandNode<>(); - map.put(this.dispatcher.getRoot(), rootCommandNode); -- fillUsableCommands(this.dispatcher.getRoot(), rootCommandNode, player.createCommandSourceStack(), map); -+ fillUsableCommands(dispatcherRootChildren, rootCommandNode, player.createCommandSourceStack(), map); // Paper - Perf: Async command map building; pass copy of children + Map, CommandNode> playerCommands = new HashMap<>(); + RootCommandNode root = new RootCommandNode<>(); + playerCommands.put(this.dispatcher.getRoot(), root); +- fillUsableCommands(this.dispatcher.getRoot(), root, player.createCommandSourceStack(), playerCommands); ++ fillUsableCommands(dispatcherRootChildren, root, player.createCommandSourceStack(), playerCommands); // Paper - Perf: Async command map building; pass copy of children + + java.util.Collection bukkit = new java.util.LinkedHashSet<>(); -+ for (CommandNode node : rootCommandNode.getChildren()) { ++ for (CommandNode node : root.getChildren()) { + bukkit.add(node.getName()); + } + // Paper start - Perf: Async command map building -+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, false).callEvent(); // Paper - Brigadier API ++ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) root, false).callEvent(); // Paper - Brigadier API + net.minecraft.server.MinecraftServer.getServer().execute(() -> { -+ runSync(player, bukkit, rootCommandNode); ++ runSync(player, bukkit, root); + }); + } + -+ private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode rootCommandNode) { ++ private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode root) { + // Paper end - Perf: Async command map building -+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, true).callEvent(); // Paper - Brigadier API ++ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) root, true).callEvent(); // Paper - Brigadier API + org.bukkit.event.player.PlayerCommandSendEvent event = new org.bukkit.event.player.PlayerCommandSendEvent(player.getBukkitEntity(), new java.util.LinkedHashSet<>(bukkit)); + event.getPlayer().getServer().getPluginManager().callEvent(event); + + // Remove labels that were removed during the event + for (String orig : bukkit) { + if (!event.getCommands().contains(orig)) { -+ rootCommandNode.removeCommand(orig); ++ root.removeCommand(orig); + } + } + // CraftBukkit end - player.connection.send(new ClientboundCommandsPacket(rootCommandNode, COMMAND_NODE_INSPECTOR)); + player.connection.send(new ClientboundCommandsPacket(root, COMMAND_NODE_INSPECTOR)); } -- private static void fillUsableCommands(CommandNode root, CommandNode current, S source, Map, CommandNode> output) { -- for (CommandNode commandNode : root.getChildren()) { -+ private static void fillUsableCommands(java.util.Collection> children, CommandNode current, S source, Map, CommandNode> output) { // Paper - Perf: Async command map building; pass copy of children -+ for (CommandNode commandNode : children) { // Paper - Perf: Async command map building; pass copy of children + private static void fillUsableCommands( +- final CommandNode source, final CommandNode target, final S commandFilter, final Map, CommandNode> converted ++ final java.util.Collection> children, final CommandNode target, final S commandFilter, final Map, CommandNode> converted // Paper - Perf: Async command map building; pass copy of children + ) { +- for (CommandNode child : source.getChildren()) { ++ for (CommandNode child : children) { // Paper - Perf: Async command map building; pass copy of children + // Paper start - Brigadier API -+ if (commandNode.clientNode != null) { -+ commandNode = commandNode.clientNode; ++ if (child.clientNode != null) { ++ child = child.clientNode; + } + // Paper end - Brigadier API -+ if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot - if (commandNode.canUse(source)) { - ArgumentBuilder argumentBuilder = commandNode.createBuilder(); ++ if (!org.spigotmc.SpigotConfig.sendNamespaced && child.getName().contains(":")) continue; // Spigot + if (child.canUse(commandFilter)) { + ArgumentBuilder builder = child.createBuilder(); + // Paper start + /* + Because of how commands can be yeeted right left and center due to bad bukkit practices @@ -226,34 +227,34 @@ + - Do this :) + */ + // Is there an invalid command redirect? -+ if (argumentBuilder.getRedirect() != null && output.get(argumentBuilder.getRedirect()) == null) { ++ if (builder.getRedirect() != null && converted.get(builder.getRedirect()) == null) { + // Create the argument builder with the same values as the specified node, but with a different literal and populated children + -+ final CommandNode redirect = argumentBuilder.getRedirect(); ++ final CommandNode redirect = builder.getRedirect(); + // Diff copied from LiteralCommand#createBuilder -+ final com.mojang.brigadier.builder.LiteralArgumentBuilder builder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(commandNode.getName()); -+ builder.requires(redirect.getRequirement()); ++ final com.mojang.brigadier.builder.LiteralArgumentBuilder redirectBuilder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(child.getName()); ++ redirectBuilder.requires(redirect.getRequirement()); + // builder.forward(redirect.getRedirect(), redirect.getRedirectModifier(), redirect.isFork()); We don't want to migrate the forward, since it's invalid. + if (redirect.getCommand() != null) { -+ builder.executes(redirect.getCommand()); ++ redirectBuilder.executes(redirect.getCommand()); + } + // Diff copied from LiteralCommand#createBuilder -+ for (final CommandNode child : redirect.getChildren()) { -+ builder.then(child); ++ for (final CommandNode redirectChild : redirect.getChildren()) { ++ redirectBuilder.then(redirectChild); + } + -+ argumentBuilder = builder; ++ builder = redirectBuilder; + } + // Paper end - if (argumentBuilder.getRedirect() != null) { - argumentBuilder.redirect(output.get(argumentBuilder.getRedirect())); + if (builder.getRedirect() != null) { + builder.redirect(converted.get(builder.getRedirect())); } -@@ -428,7 +_,7 @@ - output.put(commandNode, commandNode1); - current.addChild(commandNode1); - if (!commandNode.getChildren().isEmpty()) { -- fillUsableCommands(commandNode, commandNode1, source, output); -+ fillUsableCommands(commandNode.getChildren(), commandNode1, source, output); // Paper - Perf: Async command map building; pass copy of children +@@ -431,7 +_,7 @@ + converted.put(child, node); + target.addChild(node); + if (!child.getChildren().isEmpty()) { +- fillUsableCommands(child, node, commandFilter, converted); ++ fillUsableCommands(child.getChildren(), node, commandFilter, converted); // Paper - Perf: Async command map building; pass copy of children } } } diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch index a1eea4fbe882..b6cb3432e751 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch @@ -1,35 +1,33 @@ --- a/net/minecraft/commands/arguments/EntityArgument.java +++ b/net/minecraft/commands/arguments/EntityArgument.java -@@ -106,9 +_,14 @@ +@@ -107,9 +_,14 @@ } - private EntitySelector parse(StringReader reader, boolean allowSelectors) throws CommandSyntaxException { + private EntitySelector parse(final StringReader reader, final boolean allowSelectors) throws CommandSyntaxException { + // CraftBukkit start + return this.parse(reader, allowSelectors, false); + } -+ public EntitySelector parse(StringReader reader, boolean allowSelectors, boolean overridePermissions) throws CommandSyntaxException { ++ public EntitySelector parse(final StringReader reader, final boolean allowSelectors, final boolean overridePermissions) throws CommandSyntaxException { + // CraftBukkit end - int i = 0; - EntitySelectorParser entitySelectorParser = new EntitySelectorParser(reader, allowSelectors); -- EntitySelector entitySelector = entitySelectorParser.parse(); -+ EntitySelector entitySelector = entitySelectorParser.parse(overridePermissions); // CraftBukkit - if (entitySelector.getMaxResults() > 1 && this.single) { + int start = 0; + EntitySelectorParser parser = new EntitySelectorParser(reader, allowSelectors); +- EntitySelector selector = parser.parse(); ++ EntitySelector selector = parser.parse(overridePermissions); // CraftBukkit + if (selector.getMaxResults() > 1 && this.single) { if (this.playersOnly) { reader.setCursor(0); -@@ -130,9 +_,15 @@ - if (context.getSource() instanceof SharedSuggestionProvider sharedSuggestionProvider) { - StringReader stringReader = new StringReader(builder.getInput()); - stringReader.setCursor(builder.getStart()); +@@ -131,7 +_,13 @@ + if (contextBuilder.getSource() instanceof SharedSuggestionProvider source) { + StringReader reader = new StringReader(builder.getInput()); + reader.setCursor(builder.getStart()); +- EntitySelectorParser parser = new EntitySelectorParser(reader, source.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS)); + // Paper start - Fix EntityArgument permissions -+ final boolean permission = sharedSuggestionProvider instanceof CommandSourceStack stack ++ final boolean permission = source instanceof CommandSourceStack stack + ? stack.bypassSelectorPermissions || stack.hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS, "minecraft.command.selector") + // Only CommandSourceStack implements SharedSuggestionProvider. If *somehow* anything else ends up here, try to query its permission level, otherwise yield false. -+ : sharedSuggestionProvider.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS); - EntitySelectorParser entitySelectorParser = new EntitySelectorParser( -- stringReader, sharedSuggestionProvider.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS) -+ stringReader, permission - ); ++ : source.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS); ++ EntitySelectorParser parser = new EntitySelectorParser(reader, permission); + // Paper end - Fix EntityArgument permissions try { - entitySelectorParser.parse(); + parser.parse(); diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch index 9ec0535601f1..df018a25de7d 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch @@ -1,41 +1,42 @@ --- a/net/minecraft/commands/arguments/MessageArgument.java +++ b/net/minecraft/commands/arguments/MessageArgument.java -@@ -41,6 +_,11 @@ +@@ -41,6 +_,12 @@ - public static void resolveChatMessage(CommandContext context, String key, Consumer callback) throws CommandSyntaxException { - MessageArgument.Message message = context.getArgument(key, MessageArgument.Message.class); + public static void resolveChatMessage(final CommandContext context, final String name, final Consumer task) throws CommandSyntaxException { + MessageArgument.Message message = context.getArgument(name, MessageArgument.Message.class); + // Paper start - brig message argument support -+ resolveChatMessage(message, context, key, callback); ++ resolveChatMessage(message, context, name, task); + } -+ public static void resolveChatMessage(MessageArgument.Message message, CommandContext context, String key, Consumer callback) throws CommandSyntaxException { ++ ++ public static void resolveChatMessage(final MessageArgument.Message message, final CommandContext context, final String name, final Consumer task) throws CommandSyntaxException { + // Paper end - brig message argument support - CommandSourceStack commandSourceStack = context.getSource(); - Component component = message.resolveComponent(commandSourceStack); - CommandSigningContext signingContext = commandSourceStack.getSigningContext(); + CommandSourceStack sender = context.getSource(); + Component formatted = message.resolveComponent(sender); + CommandSigningContext signingContext = sender.getSigningContext(); @@ -55,17 +_,21 @@ - private static void resolveSignedMessage(Consumer callback, CommandSourceStack source, PlayerChatMessage message) { - MinecraftServer server = source.getServer(); - CompletableFuture completableFuture = filterPlainText(source, message); -- Component component = server.getChatDecorator().decorate(source.getPlayer(), message.decoratedContent()); -- source.getChatMessageChainer().append(completableFuture, filteredText -> { -- PlayerChatMessage playerChatMessage = message.withUnsignedContent(component).filter(filteredText.mask()); + private static void resolveSignedMessage(final Consumer task, final CommandSourceStack sender, final PlayerChatMessage signedArgument) { + MinecraftServer server = sender.getServer(); + CompletableFuture filteredFuture = filterPlainText(sender, signedArgument); +- Component decorated = server.getChatDecorator().decorate(sender.getPlayer(), signedArgument.decoratedContent()); +- sender.getChatMessageChainer().append(filteredFuture, filtered -> { +- PlayerChatMessage filteredMessage = signedArgument.withUnsignedContent(decorated).filter(filtered.mask()); + // Paper start - support asynchronous chat decoration -+ CompletableFuture componentFuture = server.getChatDecorator().decorate(source.getPlayer(), source, message.decoratedContent()); -+ source.getChatMessageChainer().append(CompletableFuture.allOf(completableFuture, componentFuture), filtered -> { -+ PlayerChatMessage playerChatMessage = message.withUnsignedContent(componentFuture.join()).filter(completableFuture.join().mask()); ++ CompletableFuture decoratedFuture = server.getChatDecorator().decorate(sender.getPlayer(), sender, signedArgument.decoratedContent()); ++ sender.getChatMessageChainer().append(CompletableFuture.allOf(filteredFuture, decoratedFuture), filtered -> { ++ PlayerChatMessage filteredMessage = signedArgument.withUnsignedContent(decoratedFuture.join()).filter(filteredFuture.join().mask()); + // Paper end - support asynchronous chat decoration - callback.accept(playerChatMessage); + task.accept(filteredMessage); }); } - private static void resolveDisguisedMessage(Consumer callback, CommandSourceStack source, PlayerChatMessage message) { - ChatDecorator chatDecorator = source.getServer().getChatDecorator(); -- Component component = chatDecorator.decorate(source.getPlayer(), message.decoratedContent()); -- callback.accept(message.withUnsignedContent(component)); + private static void resolveDisguisedMessage(final Consumer task, final CommandSourceStack sender, final PlayerChatMessage argument) { + ChatDecorator decorator = sender.getServer().getChatDecorator(); +- Component decorated = decorator.decorate(sender.getPlayer(), argument.decoratedContent()); +- task.accept(argument.withUnsignedContent(decorated)); + // Paper start - support asynchronous chat decoration -+ CompletableFuture componentFuture = chatDecorator.decorate(source.getPlayer(), source, message.decoratedContent()); -+ source.getChatMessageChainer().append(componentFuture, (result) -> callback.accept(message.withUnsignedContent(result))); ++ CompletableFuture decoratedFuture = decorator.decorate(sender.getPlayer(), sender, argument.decoratedContent()); ++ sender.getChatMessageChainer().append(decoratedFuture, result -> task.accept(argument.withUnsignedContent(result))); + // Paper end - support asynchronous chat decoration } - private static CompletableFuture filterPlainText(CommandSourceStack source, PlayerChatMessage message) { + private static CompletableFuture filterPlainText(final CommandSourceStack sender, final PlayerChatMessage message) { diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch index 936c7f5ec845..a49f86b22048 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch @@ -1,11 +1,20 @@ --- a/net/minecraft/commands/arguments/selector/EntitySelector.java +++ b/net/minecraft/commands/arguments/selector/EntitySelector.java -@@ -103,7 +_,7 @@ +@@ -50,7 +_,7 @@ + + @Override + protected String errorMessage(final String original, final CommandSyntaxException exception) { +- return "Invalid selector component: " + original + ": " + exception.getMessage(); ++ return "Invalid selector component"; // Paper - limit selector error message + } + } + ); +@@ -119,7 +_,7 @@ } - private void checkPermissions(CommandSourceStack source) throws CommandSyntaxException { -- if (this.usesSelector && !source.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS)) { -+ if (!source.bypassSelectorPermissions && this.usesSelector && !source.hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS, "minecraft.command.selector")) { // CraftBukkit // Paper - add bypass for selector perms + private void checkPermissions(final CommandSourceStack sender) throws CommandSyntaxException { +- if (this.usesSelector && !sender.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS)) { ++ if (!sender.bypassSelectorPermissions && this.usesSelector && !sender.hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS, "minecraft.command.selector")) { // CraftBukkit // Paper - add bypass for selector perms throw EntityArgument.ERROR_SELECTORS_NOT_ALLOWED.create(); } } diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelectorParser.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelectorParser.java.patch index f7a84f01766c..f58e1a909da7 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelectorParser.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelectorParser.java.patch @@ -3,16 +3,16 @@ @@ -113,6 +_,11 @@ } - public static boolean allowSelectors(S suggestionProvider) { + public static boolean allowSelectors(final S source) { + // Paper start - Fix EntityArgument permissions -+ if (suggestionProvider instanceof net.minecraft.commands.CommandSourceStack stack) { ++ if (source instanceof net.minecraft.commands.CommandSourceStack stack) { + return stack.bypassSelectorPermissions || stack.hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS, "minecraft.command.selector"); + } + // Paper end - Fix EntityArgument permissions - return suggestionProvider instanceof PermissionSetSupplier permissionSetSupplier - && permissionSetSupplier.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS); + return source instanceof PermissionSetSupplier sender && sender.permissions().hasPermission(Permissions.COMMANDS_ENTITY_SELECTORS); } -@@ -195,8 +_,10 @@ + +@@ -194,8 +_,10 @@ }; } @@ -25,7 +25,7 @@ this.suggestions = this::suggestSelector; if (!this.reader.canRead()) { throw ERROR_MISSING_SELECTOR_TYPE.createWithContext(this.reader); -@@ -458,6 +_,12 @@ +@@ -457,6 +_,12 @@ } public EntitySelector parse() throws CommandSyntaxException { @@ -38,7 +38,7 @@ this.startPosition = this.reader.getCursor(); this.suggestions = this::suggestNameOrSelector; if (this.reader.canRead() && this.reader.peek() == '@') { -@@ -466,7 +_,7 @@ +@@ -465,7 +_,7 @@ } this.reader.skip(); diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/SelectorPattern.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/SelectorPattern.java.patch deleted file mode 100644 index 970df07ef368..000000000000 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/SelectorPattern.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/commands/arguments/selector/SelectorPattern.java -+++ b/net/minecraft/commands/arguments/selector/SelectorPattern.java -@@ -13,7 +_,7 @@ - EntitySelectorParser entitySelectorParser = new EntitySelectorParser(new StringReader(pattern), true); - return DataResult.success(new SelectorPattern(pattern, entitySelectorParser.parse())); - } catch (CommandSyntaxException var2) { -- return DataResult.error(() -> "Invalid selector component: " + pattern + ": " + var2.getMessage()); -+ return DataResult.error(() -> "Invalid selector component"); // Paper - limit selector error message - } - } - diff --git a/paper-server/patches/sources/net/minecraft/core/BlockPos.java.patch b/paper-server/patches/sources/net/minecraft/core/BlockPos.java.patch index 0738cd2b3dc0..666f54016050 100644 --- a/paper-server/patches/sources/net/minecraft/core/BlockPos.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/BlockPos.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/BlockPos.java +++ b/net/minecraft/core/BlockPos.java -@@ -156,67 +_,84 @@ +@@ -155,67 +_,84 @@ @Override public BlockPos above() { @@ -9,9 +9,9 @@ } @Override - public BlockPos above(int distance) { -- return this.relative(Direction.UP, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() + distance, this.getZ()); // Paper - Perf: Optimize BlockPosition + public BlockPos above(final int steps) { +- return this.relative(Direction.UP, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() + steps, this.getZ()); // Paper - Perf: Optimize BlockPosition } @Override @@ -21,9 +21,9 @@ } @Override - public BlockPos below(int distance) { -- return this.relative(Direction.DOWN, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() - distance, this.getZ()); // Paper - Perf: Optimize BlockPosition + public BlockPos below(final int steps) { +- return this.relative(Direction.DOWN, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() - steps, this.getZ()); // Paper - Perf: Optimize BlockPosition } @Override @@ -33,9 +33,9 @@ } @Override - public BlockPos north(int distance) { -- return this.relative(Direction.NORTH, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() - distance); // Paper - Perf: Optimize BlockPosition + public BlockPos north(final int steps) { +- return this.relative(Direction.NORTH, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() - steps); // Paper - Perf: Optimize BlockPosition } @Override @@ -45,9 +45,9 @@ } @Override - public BlockPos south(int distance) { -- return this.relative(Direction.SOUTH, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() + distance); // Paper - Perf: Optimize BlockPosition + public BlockPos south(final int steps) { +- return this.relative(Direction.SOUTH, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() + steps); // Paper - Perf: Optimize BlockPosition } @Override @@ -57,9 +57,9 @@ } @Override - public BlockPos west(int distance) { -- return this.relative(Direction.WEST, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX() - distance, this.getY(), this.getZ()); // Paper - Perf: Optimize BlockPosition + public BlockPos west(final int steps) { +- return this.relative(Direction.WEST, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX() - steps, this.getY(), this.getZ()); // Paper - Perf: Optimize BlockPosition } @Override @@ -69,13 +69,13 @@ } @Override - public BlockPos east(int distance) { -- return this.relative(Direction.EAST, distance); -+ return distance == 0 ? this.immutable() : new BlockPos(this.getX() + distance, this.getY(), this.getZ()); // Paper - Perf: Optimize BlockPosition + public BlockPos east(final int steps) { +- return this.relative(Direction.EAST, steps); ++ return steps == 0 ? this.immutable() : new BlockPos(this.getX() + steps, this.getY(), this.getZ()); // Paper - Perf: Optimize BlockPosition } @Override - public BlockPos relative(Direction direction) { + public BlockPos relative(final Direction direction) { - return new BlockPos(this.getX() + direction.getStepX(), this.getY() + direction.getStepY(), this.getZ() + direction.getStepZ()); + // Paper start - Perf: Optimize BlockPosition + switch(direction) { @@ -98,10 +98,10 @@ } @Override -@@ -651,9 +_,9 @@ +@@ -662,9 +_,9 @@ } - public BlockPos.MutableBlockPos set(int x, int y, int z) { + public BlockPos.MutableBlockPos set(final int x, final int y, final int z) { - this.setX(x); - this.setY(y); - this.setZ(z); @@ -111,24 +111,24 @@ return this; } -@@ -711,19 +_,19 @@ +@@ -722,19 +_,19 @@ @Override - public BlockPos.MutableBlockPos setX(int x) { + public BlockPos.MutableBlockPos setX(final int x) { - super.setX(x); + this.x = x; // Paper - Perf: Manually inline methods in BlockPosition return this; } @Override - public BlockPos.MutableBlockPos setY(int y) { + public BlockPos.MutableBlockPos setY(final int y) { - super.setY(y); + this.y = y; // Paper - Perf: Manually inline methods in BlockPosition return this; } @Override - public BlockPos.MutableBlockPos setZ(int z) { + public BlockPos.MutableBlockPos setZ(final int z) { - super.setZ(z); + this.z = z; // Paper - Perf: Manually inline methods in BlockPosition return this; diff --git a/paper-server/patches/sources/net/minecraft/core/ClientAsset.java.patch b/paper-server/patches/sources/net/minecraft/core/ClientAsset.java.patch index 9567a6a67952..fa145277b054 100644 --- a/paper-server/patches/sources/net/minecraft/core/ClientAsset.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/ClientAsset.java.patch @@ -3,9 +3,9 @@ @@ -23,7 +_,7 @@ .map(ClientAsset.ResourceTexture::new, ClientAsset.ResourceTexture::id); - public ResourceTexture(Identifier id) { -- this(id, id.withPath(path -> "textures/" + path + ".png")); -+ this(id, id.withPath(path -> "textures/" + path + ".png")); // Paper - diff on change - io.papermc.paper.registry.data.client.ClientAssetImpl#pathFromIdentifier + public ResourceTexture(final Identifier texture) { +- this(texture, texture.withPath(path -> "textures/" + path + ".png")); ++ this(texture, texture.withPath(path -> "textures/" + path + ".png")); // Paper - diff on change - io.papermc.paper.registry.data.client.ClientAssetImpl#pathFromIdentifier } } diff --git a/paper-server/patches/sources/net/minecraft/core/Direction.java.patch b/paper-server/patches/sources/net/minecraft/core/Direction.java.patch index 4b822775682c..4d521d485ece 100644 --- a/paper-server/patches/sources/net/minecraft/core/Direction.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Direction.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/core/Direction.java +++ b/net/minecraft/core/Direction.java -@@ -65,6 +_,12 @@ - .sorted(Comparator.comparingInt(direction -> direction.data2d)) +@@ -63,6 +_,12 @@ + .sorted(Comparator.comparingInt(d -> d.data2d)) .toArray(Direction[]::new); + // Paper start - Perf: Inline shift direction fields @@ -13,7 +13,7 @@ private Direction( final int data3d, final int oppositeIndex, -@@ -83,6 +_,11 @@ +@@ -81,6 +_,11 @@ this.normal = normal; this.normalVec3 = Vec3.atLowerCornerOf(normal); this.normalVec3f = new Vector3f(normal.getX(), normal.getY(), normal.getZ()); @@ -24,8 +24,8 @@ + // Paper end - Perf: Inline shift direction fields } - public static Direction[] orderedByNearest(Entity entity) { -@@ -255,15 +_,15 @@ + public static Direction[] orderedByNearest(final Entity entity) { +@@ -253,15 +_,15 @@ } public int getStepX() { diff --git a/paper-server/patches/sources/net/minecraft/core/Holder.java.patch b/paper-server/patches/sources/net/minecraft/core/Holder.java.patch index 34c31f6e8258..9e9ae320bc73 100644 --- a/paper-server/patches/sources/net/minecraft/core/Holder.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Holder.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/core/Holder.java +++ b/net/minecraft/core/Holder.java -@@ -227,7 +_,7 @@ +@@ -248,7 +_,7 @@ } - void bindTags(Collection> tags) { + void bindTags(final Collection> tags) { - this.tags = Set.copyOf(tags); + this.tags = it.unimi.dsi.fastutil.objects.ReferenceSets.unmodifiable(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(tags)); // Paper - use reference set because TagKey are interned } - @Override + public void bindComponents(final DataComponentMap components) { diff --git a/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch b/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch index 17edc3610ce4..fb7582690da5 100644 --- a/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/HolderLookup.java +++ b/net/minecraft/core/HolderLookup.java -@@ -68,6 +_,9 @@ +@@ -69,6 +_,9 @@ } public interface RegistryLookup extends HolderLookup, HolderOwner { @@ -10,21 +10,21 @@ ResourceKey> key(); Lifecycle registryLifecycle(); -@@ -80,6 +_,13 @@ +@@ -83,6 +_,13 @@ + Objects.requireNonNull(RegistryLookup.this); + } - default HolderLookup.RegistryLookup filterElements(final Predicate predicate) { - return new HolderLookup.RegistryLookup.Delegate() { + // Paper start - add getValueForCopying + @Override + public Optional getValueForCopying(final ResourceKey resourceKey) { -+ return this.parent().getValueForCopying(resourceKey).filter(predicate); ++ return this.parent().getValueForCopying(resourceKey).filter(filter); + } + // Paper end - add getValueForCopying + @Override public HolderLookup.RegistryLookup parent() { return RegistryLookup.this; -@@ -99,6 +_,13 @@ +@@ -102,6 +_,13 @@ public interface Delegate extends HolderLookup.RegistryLookup { HolderLookup.RegistryLookup parent(); diff --git a/paper-server/patches/sources/net/minecraft/core/HolderSet.java.patch b/paper-server/patches/sources/net/minecraft/core/HolderSet.java.patch index 353c12b7d869..46c4d12eef7f 100644 --- a/paper-server/patches/sources/net/minecraft/core/HolderSet.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/HolderSet.java.patch @@ -6,19 +6,19 @@ private @Nullable List> contents; + private @Nullable Set> typedKeys; // Paper - cache typed key set for constant contains calls - Named(HolderOwner owner, TagKey key) { + Named(final HolderOwner owner, final TagKey key) { this.owner = owner; @@ -172,6 +_,7 @@ - void bind(List> contents) { + void bind(final List> contents) { this.contents = List.copyOf(contents); + this.typedKeys = null; // Paper - reset if tag is re-bound } public TagKey key() { @@ -216,5 +_,15 @@ - public boolean canSerializeIn(HolderOwner owner) { - return this.owner.canSerializeIn(owner); + public boolean canSerializeIn(final HolderOwner context) { + return this.owner.canSerializeIn(context); } + + // Paper start - cache typed key set for constant contains calls diff --git a/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch b/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch index 1c658944e836..3ea652f70b8c 100644 --- a/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch @@ -1,22 +1,23 @@ --- a/net/minecraft/core/MappedRegistry.java +++ b/net/minecraft/core/MappedRegistry.java -@@ -32,16 +_,24 @@ +@@ -33,17 +_,25 @@ public class MappedRegistry implements WritableRegistry { private final ResourceKey> key; private final ObjectList> byId = new ObjectArrayList<>(256); -- private final Reference2IntMap toId = Util.make(new Reference2IntOpenHashMap<>(), map -> map.defaultReturnValue(-1)); +- private final Reference2IntMap toId = Util.make(new Reference2IntOpenHashMap<>(), t -> t.defaultReturnValue(-1)); - private final Map> byLocation = new HashMap<>(); - private final Map, Holder.Reference> byKey = new HashMap<>(); - private final Map> byValue = new IdentityHashMap<>(); - private final Map, RegistrationInfo> registrationInfos = new IdentityHashMap<>(); -+ private final Reference2IntMap toId = Util.make(new Reference2IntOpenHashMap<>(2048), map -> map.defaultReturnValue(-1)); // Paper - Perf: Use bigger expected size to reduce collisions ++ private final Reference2IntMap toId = Util.make(new Reference2IntOpenHashMap<>(2048), t -> t.defaultReturnValue(-1)); // Paper - Perf: Use bigger expected size to reduce collisions + private final Map> byLocation = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions + private final Map, Holder.Reference> byKey = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions + private final Map> byValue = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions + private final Map, RegistrationInfo> registrationInfos = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions private Lifecycle registryLifecycle; private final Map, HolderSet.Named> frozenTags = new IdentityHashMap<>(); - MappedRegistry.TagSet allTags = MappedRegistry.TagSet.unbound(); + private MappedRegistry.TagSet allTags = MappedRegistry.TagSet.unbound(); + private @Nullable DataComponentLookup componentLookup; private boolean frozen; private @Nullable Map> unregisteredIntrusiveHolders; + // Paper start - support pre-filling in registry mod API @@ -30,23 +31,23 @@ @Override public Stream> listTags() { -@@ -112,6 +_,7 @@ - this.toId.put(value, size); +@@ -114,6 +_,7 @@ + this.toId.put(value, newId); this.registrationInfos.put(key, registrationInfo); this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); + this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API - return reference; + return holder; } } -@@ -268,6 +_,7 @@ +@@ -275,6 +_,7 @@ return this; } else { this.frozen = true; + this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API - this.byValue.forEach((object, reference) -> reference.bindValue((T)object)); - List list = this.byKey + this.byValue.forEach((value, holder) -> holder.bindValue((T)value)); + List unboundEntries = this.byKey .entrySet() -@@ -502,4 +_,13 @@ +@@ -522,4 +_,13 @@ Stream> getTags(); } diff --git a/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch b/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch index 150d368bed7f..3f34cbfa1e2b 100644 --- a/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/core/RegistrySetBuilder.java +++ b/net/minecraft/core/RegistrySetBuilder.java -@@ -41,6 +_,13 @@ - final Map, Holder.Reference> elements +@@ -42,6 +_,13 @@ + final Map, Holder.Reference> entries ) { return new RegistrySetBuilder.EmptyTagRegistryLookup(owner) { + // Paper start - add getValueForCopying method @@ -13,9 +13,9 @@ + @Override public ResourceKey> key() { - return registryKey; -@@ -121,6 +_,13 @@ - public Optional> lookup(ResourceKey> registryKey) { + return key; +@@ -128,6 +_,13 @@ + public Optional> lookup(final ResourceKey> registryKey) { return getEntry(registryKey).map(Entry::opsInfo); } + diff --git a/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch b/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch index 39a00218deeb..1aeb50910287 100644 --- a/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/core/Rotations.java +++ b/net/minecraft/core/Rotations.java @@ -26,11 +_,22 @@ - buffer.writeFloat(value.z); + output.writeFloat(value.z); } }; + // Paper start - add internal method for skipping validation for plugins using userdev diff --git a/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch b/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch index 9b131d3e85a4..d2371dbfce08 100644 --- a/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/Vec3i.java +++ b/net/minecraft/core/Vec3i.java -@@ -23,9 +_,9 @@ +@@ -22,9 +_,9 @@ ByteBufCodecs.VAR_INT, Vec3i::getX, ByteBufCodecs.VAR_INT, Vec3i::getY, ByteBufCodecs.VAR_INT, Vec3i::getZ, Vec3i::new ); public static final Vec3i ZERO = new Vec3i(0, 0, 0); @@ -11,15 +11,15 @@ + protected int y; // Paper - Perf: Manually inline methods in BlockPosition; protected + protected int z; // Paper - Perf: Manually inline methods in BlockPosition; protected - public static Codec offsetCodec(int maxOffset) { + public static Codec offsetCodec(final int maxOffsetPerAxis) { return CODEC.validate( -@@ -42,12 +_,12 @@ +@@ -41,12 +_,12 @@ } @Override -- public boolean equals(Object other) { -+ public final boolean equals(Object other) { // Paper - Perf: Final for inline - return this == other || other instanceof Vec3i vec3i && this.getX() == vec3i.getX() && this.getY() == vec3i.getY() && this.getZ() == vec3i.getZ(); +- public boolean equals(final Object o) { ++ public final boolean equals(final Object o) { // Paper - Perf: Final for inline + return this == o || o instanceof Vec3i vec3i && this.getX() == vec3i.getX() && this.getY() == vec3i.getY() && this.getZ() == vec3i.getZ(); } @Override @@ -28,7 +28,7 @@ return (this.getY() + this.getZ() * 31) * 31 + this.getX(); } -@@ -60,15 +_,15 @@ +@@ -59,15 +_,15 @@ } } @@ -47,7 +47,7 @@ return this.z; } -@@ -250,4 +_,11 @@ +@@ -247,4 +_,11 @@ public String toShortString() { return this.getX() + ", " + this.getY() + ", " + this.getZ(); } diff --git a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch index a741db3c36ac..70d5f3e67fab 100644 --- a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch @@ -1,302 +1,14 @@ --- a/net/minecraft/core/cauldron/CauldronInteraction.java +++ b/net/minecraft/core/cauldron/CauldronInteraction.java -@@ -42,26 +_,31 @@ +@@ -15,9 +_,9 @@ - static CauldronInteraction.InteractionMap newInteractionMap(String name) { - Object2ObjectOpenHashMap map = new Object2ObjectOpenHashMap<>(); -- map.defaultReturnValue((state, level, pos, player, hand, stack) -> InteractionResult.TRY_WITH_EMPTY_HAND); -+ map.defaultReturnValue((state, level, pos, player, hand, stack, hitDirection) -> InteractionResult.TRY_WITH_EMPTY_HAND); // Paper - add hitDirection - CauldronInteraction.InteractionMap interactionMap = new CauldronInteraction.InteractionMap(name, map); - INTERACTIONS.put(name, interactionMap); - return interactionMap; - } + @FunctionalInterface + public interface CauldronInteraction { +- CauldronInteraction DEFAULT = (var0, var1, var2, var3, var4, var5) -> InteractionResult.TRY_WITH_EMPTY_HAND; ++ CauldronInteraction DEFAULT = (var0, var1, var2, var3, var4, var5, var6) -> InteractionResult.TRY_WITH_EMPTY_HAND; // Paper - add hitDirection -- InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack); -+ InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, final net.minecraft.core.Direction hitDirection); // Paper - add hitDirection +- InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand); ++ InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand, net.minecraft.core.Direction hitDirection); // Paper - add hitDirection - static void bootStrap() { - Map map = EMPTY.map(); - addDefaultInteractions(map); -- map.put(Items.POTION, (state, level, pos, player, hand, stack) -> { -+ map.put(Items.POTION, (state, level, pos, player, hand, stack, hitDirection) -> { // Paper - add hitDirection - PotionContents potionContents = stack.get(DataComponents.POTION_CONTENTS); - if (potionContents != null && potionContents.is(Potions.WATER)) { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.changeLevel(level, pos, Blocks.WATER_CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - Item item = stack.getItem(); - player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE))); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(item)); -- level.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); -+ // level.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit - level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PLACE, pos); - } -@@ -75,7 +_,7 @@ - addDefaultInteractions(map1); - map1.put( - Items.BUCKET, -- (state, level, pos, player, hand, stack) -> fillBucket( -+ (state, level, pos, player, hand, stack, hitDirection) -> fillBucket( // Paper - add hitDirection - state, - level, - pos, -@@ -84,33 +_,43 @@ - stack, - new ItemStack(Items.WATER_BUCKET), - blockState -> blockState.getValue(LayeredCauldronBlock.LEVEL) == 3, -- SoundEvents.BUCKET_FILL -+ SoundEvents.BUCKET_FILL, hitDirection // Paper - add hitDirection - ) - ); -- map1.put(Items.GLASS_BOTTLE, (state, level, pos, player, hand, stack) -> { -+ map1.put(Items.GLASS_BOTTLE, (state, level, pos, player, hand, stack, hitDirection) -> { // Paper - add hitDirection - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - Item item = stack.getItem(); - player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, PotionContents.createItemStack(Items.POTION, Potions.WATER))); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(item)); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); - } - - return InteractionResult.SUCCESS; - }); -- map1.put(Items.POTION, (state, level, pos, player, hand, stack) -> { -+ map1.put(Items.POTION, (state, level, pos, player, hand, stack, hitDirection) -> { // Paper - add hitDirection - if (state.getValue(LayeredCauldronBlock.LEVEL) == 3) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - PotionContents potionContents = stack.get(DataComponents.POTION_CONTENTS); - if (potionContents != null && potionContents.is(Potions.WATER)) { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.changeLevel(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE))); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(stack.getItem())); -- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); -+ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit - level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PLACE, pos); - } -@@ -162,15 +_,15 @@ - Map map2 = LAVA.map(); - map2.put( - Items.BUCKET, -- (state, level, pos, player, hand, stack) -> fillBucket( -- state, level, pos, player, hand, stack, new ItemStack(Items.LAVA_BUCKET), blockState -> true, SoundEvents.BUCKET_FILL_LAVA -+ (state, level, pos, player, hand, stack, hitDirection) -> fillBucket( // Paper - add hitDirection -+ state, level, pos, player, hand, stack, new ItemStack(Items.LAVA_BUCKET), blockState -> true, SoundEvents.BUCKET_FILL_LAVA, hitDirection // Paper - add hitDirection - ) - ); - addDefaultInteractions(map2); - Map map3 = POWDER_SNOW.map(); - map3.put( - Items.BUCKET, -- (state, level, pos, player, hand, stack) -> fillBucket( -+ (state, level, pos, player, hand, stack, hitDirection) -> fillBucket( // Paper - add hitDirection - state, - level, - pos, -@@ -179,7 +_,7 @@ - stack, - new ItemStack(Items.POWDER_SNOW_BUCKET), - blockState -> blockState.getValue(LayeredCauldronBlock.LEVEL) == 3, -- SoundEvents.BUCKET_FILL_POWDER_SNOW -+ SoundEvents.BUCKET_FILL_POWDER_SNOW, hitDirection // Paper - add hitDirection - ) - ); - addDefaultInteractions(map3); -@@ -202,15 +_,35 @@ - Predicate statePredicate, - SoundEvent fillSound - ) { -+ // Paper start - add hitDirection -+ return fillBucket(state, level, pos, player, hand, emptyStack, filledStack, statePredicate, fillSound, null); // Paper - add hitDirection -+ } -+ -+ static InteractionResult fillBucket(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack emptyStack, ItemStack filledStack, Predicate statePredicate, SoundEvent fillSound, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) { -+ // Paper end - add hitDirection - if (!statePredicate.test(state)) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // Paper start - fire PlayerBucketFillEvent -+ if (hitDirection != null) { -+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, emptyStack, filledStack.getItem(), hand); -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ filledStack = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; -+ } -+ // Paper end - fire PlayerBucketFillEvent -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.changeLevel(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - Item item = emptyStack.getItem(); - player.setItemInHand(hand, ItemUtils.createFilledResult(emptyStack, player, filledStack)); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(item)); -- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); -+ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit - level.playSound(null, pos, fillSound, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); - } -@@ -222,12 +_,33 @@ - static InteractionResult emptyBucket( - Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, BlockState state, SoundEvent emptySound - ) { -+ // Paper start - add hitDirection -+ return emptyBucket(level, pos, player, hand, filledStack, state, emptySound, null); -+ } -+ -+ static InteractionResult emptyBucket(Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, BlockState state, SoundEvent emptySound, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) { -+ // Paper end - add hitDirection - if (!level.isClientSide()) { -+ // Paper start - fire PlayerBucketEmptyEvent -+ ItemStack output = new ItemStack(Items.BUCKET); -+ if (hitDirection != null) { -+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent(level, player, pos, pos, hitDirection, filledStack, hand); -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ output = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; -+ } -+ // Paper end - fire PlayerBucketEmptyEvent -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.changeLevel(level, pos, state, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - Item item = filledStack.getItem(); -- player.setItemInHand(hand, ItemUtils.createFilledResult(filledStack, player, new ItemStack(Items.BUCKET))); -+ player.setItemInHand(hand, ItemUtils.createFilledResult(filledStack, player, output)); // Paper - player.awardStat(Stats.FILL_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(item)); -- level.setBlockAndUpdate(pos, state); -+ // level.setBlockAndUpdate(pos, state); // CraftBukkit - level.playSound(null, pos, emptySound, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PLACE, pos); - } -@@ -236,23 +_,23 @@ - } - - private static InteractionResult fillWaterInteraction( -- BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack -+ BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection - ) { - return emptyBucket( -- level, pos, player, hand, filledStack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY -+ level, pos, player, hand, filledStack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY, hitDirection // Paper - add hitDirection - ); - } - - private static InteractionResult fillLavaInteraction( -- BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack -+ BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection - ) { - return (InteractionResult)(isUnderWater(level, pos) - ? InteractionResult.CONSUME -- : emptyBucket(level, pos, player, hand, filledStack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA)); -+ : emptyBucket(level, pos, player, hand, filledStack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection)); // Paper - add hitDirection - } - - private static InteractionResult fillPowderSnowInteraction( -- BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack -+ BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection - ) { - return (InteractionResult)(isUnderWater(level, pos) - ? InteractionResult.CONSUME -@@ -263,53 +_,68 @@ - hand, - filledStack, - Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), -- SoundEvents.BUCKET_EMPTY_POWDER_SNOW -+ SoundEvents.BUCKET_EMPTY_POWDER_SNOW, hitDirection // Paper - add hitDirection - )); - } - -- private static InteractionResult shulkerBoxInteraction(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack) { -+ private static InteractionResult shulkerBoxInteraction(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, final net.minecraft.core.Direction hitDirection) { // Paper - add hitDirection - Block block = Block.byItem(stack.getItem()); - if (!(block instanceof ShulkerBoxBlock)) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - ItemStack itemStack = stack.transmuteCopy(Blocks.SHULKER_BOX, 1); - player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, itemStack, false)); - player.awardStat(Stats.CLEAN_SHULKER_BOX); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } - - return InteractionResult.SUCCESS; - } - } - -- private static InteractionResult bannerInteraction(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack) { -+ private static InteractionResult bannerInteraction(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, final net.minecraft.core.Direction hitDirection) { // Paper - add hitDirection - BannerPatternLayers bannerPatternLayers = stack.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); - if (bannerPatternLayers.layers().isEmpty()) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - ItemStack itemStack = stack.copyWithCount(1); - itemStack.set(DataComponents.BANNER_PATTERNS, bannerPatternLayers.removeLast()); - player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, itemStack, false)); - player.awardStat(Stats.CLEAN_BANNER); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } - - return InteractionResult.SUCCESS; - } - } - -- private static InteractionResult dyedItemIteration(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack) { -+ private static InteractionResult dyedItemIteration(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, final net.minecraft.core.Direction hitDirection) { // Paper - add hitDirection - if (!stack.is(ItemTags.DYEABLE)) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else if (!stack.has(DataComponents.DYED_COLOR)) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - stack.remove(DataComponents.DYED_COLOR); - player.awardStat(Stats.CLEAN_ARMOR); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } - - return InteractionResult.SUCCESS; + public static class Dispatcher { + private final Map, CauldronInteraction> tags = new HashMap<>(); diff --git a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch new file mode 100644 index 000000000000..837e2aec338a --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch @@ -0,0 +1,312 @@ +--- a/net/minecraft/core/cauldron/CauldronInteractions.java ++++ b/net/minecraft/core/cauldron/CauldronInteractions.java +@@ -46,15 +_,20 @@ + + public static void bootStrap() { + addDefaultInteractions(EMPTY); +- EMPTY.put(Items.POTION, (var0, level, pos, player, hand, itemInHand) -> { ++ EMPTY.put(Items.POTION, (var0, level, pos, player, hand, itemInHand, hitDirection) -> { // Paper - add hitDirection + PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS); + if (potion != null && potion.is(Potions.WATER)) { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.changeLevel(level, pos, Blocks.WATER_CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + Item usedItem = itemInHand.getItem(); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE))); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(usedItem)); +- level.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); ++ // level.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit + level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PLACE, pos); + } +@@ -67,7 +_,7 @@ + addDefaultInteractions(WATER); + WATER.put( + Items.BUCKET, +- (state, level, pos, player, hand, itemInHand) -> fillBucket( ++ (state, level, pos, player, hand, itemInHand, hitDirection) -> fillBucket( // Paper - add hitDirection + state, + level, + pos, +@@ -76,33 +_,43 @@ + itemInHand, + new ItemStack(Items.WATER_BUCKET), + s -> s.getValue(LayeredCauldronBlock.LEVEL) == 3, +- SoundEvents.BUCKET_FILL ++ SoundEvents.BUCKET_FILL, hitDirection // Paper - add hitDirection + ) + ); +- WATER.put(Items.GLASS_BOTTLE, (state, level, pos, player, hand, itemInHand) -> { ++ WATER.put(Items.GLASS_BOTTLE, (state, level, pos, player, hand, itemInHand, hitDirection) -> { // Paper - add hitDirection + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + Item usedItem = itemInHand.getItem(); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, PotionContents.createItemStack(Items.POTION, Potions.WATER))); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(usedItem)); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); + } + + return InteractionResult.SUCCESS; + }); +- WATER.put(Items.POTION, (state, level, pos, player, hand, itemInHand) -> { ++ WATER.put(Items.POTION, (state, level, pos, player, hand, itemInHand, hitDirection) -> { // Paper - add hitDirection + if (state.getValue(LayeredCauldronBlock.LEVEL) == 3) { + return InteractionResult.TRY_WITH_EMPTY_HAND; + } else { + PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS); + if (potion != null && potion.is(Potions.WATER)) { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.changeLevel(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE))); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(itemInHand.getItem())); +- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); ++ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit + level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PLACE, pos); + } +@@ -148,14 +_,14 @@ + WATER.put(Items.YELLOW_SHULKER_BOX, CauldronInteractions::shulkerBoxInteraction); + LAVA.put( + Items.BUCKET, +- (state, level, pos, player, hand, itemInHand) -> fillBucket( +- state, level, pos, player, hand, itemInHand, new ItemStack(Items.LAVA_BUCKET), var0x -> true, SoundEvents.BUCKET_FILL_LAVA ++ (state, level, pos, player, hand, itemInHand, hitDirection) -> fillBucket( // Paper - add hitDirection ++ state, level, pos, player, hand, itemInHand, new ItemStack(Items.LAVA_BUCKET), var0x -> true, SoundEvents.BUCKET_FILL_LAVA, hitDirection // Paper - add hitDirection + ) + ); + addDefaultInteractions(LAVA); + POWDER_SNOW.put( + Items.BUCKET, +- (state, level, pos, player, hand, itemInHand) -> fillBucket( ++ (state, level, pos, player, hand, itemInHand, hitDirection) -> fillBucket( // Paper - add hitDirection + state, + level, + pos, +@@ -164,7 +_,7 @@ + itemInHand, + new ItemStack(Items.POWDER_SNOW_BUCKET), + s -> s.getValue(LayeredCauldronBlock.LEVEL) == 3, +- SoundEvents.BUCKET_FILL_POWDER_SNOW ++ SoundEvents.BUCKET_FILL_POWDER_SNOW, hitDirection // Paper - add hitDirection + ) + ); + addDefaultInteractions(POWDER_SNOW); +@@ -187,15 +_,46 @@ + final Predicate canFill, + final SoundEvent soundEvent + ) { ++ // Paper start - add hitDirection ++ return fillBucket(state, level, pos, player, hand, itemInHand, newItem, canFill, soundEvent, null); ++ } ++ ++ static InteractionResult fillBucket( ++ final BlockState state, ++ final Level level, ++ final BlockPos pos, ++ final Player player, ++ final InteractionHand hand, ++ final ItemStack itemInHand, ++ ItemStack newItem, ++ final Predicate canFill, ++ final SoundEvent soundEvent, ++ final net.minecraft.core.@org.jspecify.annotations.Nullable Direction hitDirection ++ ) { ++ // Paper end - add hitDirection + if (!canFill.test(state)) { + return InteractionResult.TRY_WITH_EMPTY_HAND; + } else { + if (!level.isClientSide()) { ++ // Paper start - fire PlayerBucketFillEvent ++ if (hitDirection != null) { ++ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, itemInHand, newItem.getItem(), hand); ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ newItem = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; ++ } ++ // Paper end - fire PlayerBucketFillEvent ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.changeLevel(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + Item itemUsed = itemInHand.getItem(); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, newItem)); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(itemUsed)); +- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); ++ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit + level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); + } +@@ -213,12 +_,42 @@ + final BlockState newState, + final SoundEvent soundEvent + ) { ++ // Paper start - add hitDirection ++ return emptyBucket(level, pos, player, hand, itemInHand, newState, soundEvent, null); ++ } ++ ++ static InteractionResult emptyBucket( ++ final Level level, ++ final BlockPos pos, ++ final Player player, ++ final InteractionHand hand, ++ final ItemStack itemInHand, ++ final BlockState newState, ++ final SoundEvent soundEvent, ++ final net.minecraft.core.@org.jspecify.annotations.Nullable Direction hitDirection ++ ) { ++ // Paper end - add hitDirection + if (!level.isClientSide()) { ++ // Paper start - fire PlayerBucketEmptyEvent ++ ItemStack output = new ItemStack(Items.BUCKET); ++ if (hitDirection != null) { ++ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent(level, player, pos, pos, hitDirection, itemInHand, hand); ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ output = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; ++ } ++ // Paper end - fire PlayerBucketEmptyEvent ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.changeLevel(level, pos, newState, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + Item itemUsed = itemInHand.getItem(); +- player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.BUCKET))); ++ player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, output)); // Paper + player.awardStat(Stats.FILL_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(itemUsed)); +- level.setBlockAndUpdate(pos, newState); ++ // level.setBlockAndUpdate(pos, newState); // CraftBukkit + level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PLACE, pos); + } +@@ -227,23 +_,23 @@ + } + + private static InteractionResult fillWaterInteraction( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + return emptyBucket( +- level, pos, player, hand, itemInHand, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY ++ level, pos, player, hand, itemInHand, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY, hitDirection // Paper - add hitDirection + ); + } + + private static InteractionResult fillLavaInteraction( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + return (InteractionResult)(isUnderWater(level, pos) + ? InteractionResult.CONSUME +- : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA)); ++ : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection)); // Paper - add hitDirection + } + + private static InteractionResult fillPowderSnowInteraction( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + return (InteractionResult)(isUnderWater(level, pos) + ? InteractionResult.CONSUME +@@ -254,22 +_,27 @@ + hand, + itemInHand, + Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), +- SoundEvents.BUCKET_EMPTY_POWDER_SNOW ++ SoundEvents.BUCKET_EMPTY_POWDER_SNOW, hitDirection // Paper - add hitDirection + )); + } + + private static InteractionResult shulkerBoxInteraction( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + Block block = Block.byItem(itemInHand.getItem()); + if (!(block instanceof ShulkerBoxBlock)) { + return InteractionResult.TRY_WITH_EMPTY_HAND; + } else { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + ItemStack cleanedShulkerBox = itemInHand.transmuteCopy(Blocks.SHULKER_BOX, 1); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedShulkerBox, false)); + player.awardStat(Stats.CLEAN_SHULKER_BOX); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; +@@ -277,18 +_,23 @@ + } + + private static InteractionResult bannerInteraction( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + BannerPatternLayers patterns = itemInHand.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); + if (patterns.layers().isEmpty()) { + return InteractionResult.TRY_WITH_EMPTY_HAND; + } else { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + ItemStack cleanedBanner = itemInHand.copyWithCount(1); + cleanedBanner.set(DataComponents.BANNER_PATTERNS, patterns.removeLast()); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedBanner, false)); + player.awardStat(Stats.CLEAN_BANNER); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; +@@ -296,15 +_,20 @@ + } + + private static InteractionResult dyedItemIteration( +- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand ++ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection + ) { + if (!itemInHand.has(DataComponents.DYED_COLOR)) { + return InteractionResult.TRY_WITH_EMPTY_HAND; + } else { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + itemInHand.remove(DataComponents.DYED_COLOR); + player.awardStat(Stats.CLEAN_ARMOR); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; diff --git a/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch b/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch index 52040ac041fe..1de1c463cb95 100644 --- a/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch @@ -1,52 +1,52 @@ --- a/net/minecraft/core/component/DataComponentPatch.java +++ b/net/minecraft/core/component/DataComponentPatch.java @@ -106,6 +_,11 @@ - buffer.writeVarInt(0); - buffer.writeVarInt(0); + output.writeVarInt(0); + output.writeVarInt(0); } else { + // Paper start - data sanitization for items -+ final io.papermc.paper.util.sanitizer.ItemObfuscationSession itemObfuscationSession = value.map.isEmpty() ++ final io.papermc.paper.util.sanitizer.ItemObfuscationSession itemObfuscationSession = patch.map.isEmpty() + ? null // Avoid thread local lookup of current session if it won't be needed anyway. + : io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(); + // Paper end - data sanitization for items - int i = 0; - int i1 = 0; + int positiveCount = 0; + int negativeCount = 0; @@ -113,7 +_,7 @@ - value.map + patch.map )) { if (entry.getValue().isPresent()) { -- i++; -+ if (!io.papermc.paper.util.sanitizer.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) i++; // Paper - data sanitization for items +- positiveCount++; ++ if (!io.papermc.paper.util.sanitizer.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) positiveCount++; // Paper - data sanitization for items } else { - i1++; + negativeCount++; } @@ -126,6 +_,7 @@ - value.map + patch.map )) { - Optional optional = entryx.getValue(); -+ optional = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items - if (optional.isPresent()) { - DataComponentType dataComponentType = entryx.getKey(); - DataComponentType.STREAM_CODEC.encode(buffer, dataComponentType); + Optional value = entryx.getValue(); ++ value = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items + if (value.isPresent()) { + DataComponentType type = entryx.getKey(); + DataComponentType.STREAM_CODEC.encode(output, type); @@ -145,7 +_,13 @@ } - private void encodeComponent(RegistryFriendlyByteBuf buffer, DataComponentType component, Object value) { -- codecGetter.apply(component).encode(buffer, (T)value); + private void encodeComponent(final RegistryFriendlyByteBuf output, final DataComponentType type, final Object value) { +- codecGetter.apply(type).encode(output, (T)value); + // Paper start - codec errors of random anonymous classes are useless + try { -+ codecGetter.apply(component).encode(buffer, (T)value); ++ codecGetter.apply(type).encode(output, (T)value); + } catch (final Exception e) { -+ throw new RuntimeException("Error encoding component " + component, e); ++ throw new RuntimeException("Error encoding component " + type, e); + } + // Paper end - codec errors of random anonymous classes are useless } }; } -@@ -248,6 +_,42 @@ +@@ -255,6 +_,42 @@ - Builder() { + private Builder() { } + + // CraftBukkit start @@ -85,5 +85,5 @@ + } + // CraftBukkit end - public DataComponentPatch.Builder set(DataComponentType component, T value) { - this.map.put(component, Optional.of(value)); + public DataComponentPatch.Builder set(final DataComponentType type, final T value) { + this.map.put(type, Optional.of(value)); diff --git a/paper-server/patches/sources/net/minecraft/core/component/DataComponents.java.patch b/paper-server/patches/sources/net/minecraft/core/component/DataComponents.java.patch index 738c56efba60..35439836aeff 100644 --- a/paper-server/patches/sources/net/minecraft/core/component/DataComponents.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/component/DataComponents.java.patch @@ -1,24 +1,24 @@ --- a/net/minecraft/core/component/DataComponents.java +++ b/net/minecraft/core/component/DataComponents.java -@@ -236,10 +_,10 @@ - "map_post_processing", builder -> builder.networkSynchronized(MapPostProcessing.STREAM_CODEC) +@@ -231,10 +_,10 @@ + "map_post_processing", b -> b.networkSynchronized(MapPostProcessing.STREAM_CODEC) ); public static final DataComponentType CHARGED_PROJECTILES = register( -- "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(ChargedProjectiles.STREAM_CODEC).cacheEncoding() -+ "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles +- "charged_projectiles", b -> b.persistent(ChargedProjectiles.CODEC).networkSynchronized(ChargedProjectiles.STREAM_CODEC).cacheEncoding() ++ "charged_projectiles", b -> b.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles ); public static final DataComponentType BUNDLE_CONTENTS = register( -- "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(BundleContents.STREAM_CODEC).cacheEncoding() -+ "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents +- "bundle_contents", b -> b.persistent(BundleContents.CODEC).networkSynchronized(BundleContents.STREAM_CODEC).cacheEncoding() ++ "bundle_contents", b -> b.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents ); public static final DataComponentType POTION_CONTENTS = register( - "potion_contents", builder -> builder.persistent(PotionContents.CODEC).networkSynchronized(PotionContents.STREAM_CODEC).cacheEncoding() -@@ -322,7 +_,7 @@ - "pot_decorations", builder -> builder.persistent(PotDecorations.CODEC).networkSynchronized(PotDecorations.STREAM_CODEC).cacheEncoding() + "potion_contents", b -> b.persistent(PotionContents.CODEC).networkSynchronized(PotionContents.STREAM_CODEC).cacheEncoding() +@@ -314,7 +_,7 @@ + "pot_decorations", b -> b.persistent(PotDecorations.CODEC).networkSynchronized(PotDecorations.STREAM_CODEC).cacheEncoding() ); public static final DataComponentType CONTAINER = register( -- "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(ItemContainerContents.STREAM_CODEC).cacheEncoding() -+ "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CONTAINER).cacheEncoding() // Paper - sanitize container contents +- "container", b -> b.persistent(ItemContainerContents.CODEC).networkSynchronized(ItemContainerContents.STREAM_CODEC).cacheEncoding() ++ "container", b -> b.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CONTAINER).cacheEncoding() // Paper - sanitize container contents ); public static final DataComponentType BLOCK_STATE = register( - "block_state", builder -> builder.persistent(BlockItemStateProperties.CODEC).networkSynchronized(BlockItemStateProperties.STREAM_CODEC).cacheEncoding() + "block_state", b -> b.persistent(BlockItemStateProperties.CODEC).networkSynchronized(BlockItemStateProperties.STREAM_CODEC).cacheEncoding() diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java.patch index cdf7f08ddbe2..5fe9b0cd7828 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java @@ -41,13 +_,36 @@ - d4 = 0.0; + yOffset = 0.0; } + // CraftBukkit start -+ ItemStack singleItemStack = item.copyWithCount(1); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); ++ ItemStack singleItemStack = dispensed.copyWithCount(1); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3)); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(spawnX, spawnY + yOffset, spawnZ)); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -21,22 +21,22 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + // CraftBukkit end - AbstractBoat abstractBoat = this.type.create(serverLevel, EntitySpawnReason.DISPENSER); - if (abstractBoat != null) { -- abstractBoat.setInitialPos(d1, d2 + d4, d3); -+ abstractBoat.setInitialPos(event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); // CraftBukkit - EntityType.createDefaultStackConfig(serverLevel, item, null).accept(abstractBoat); - abstractBoat.setYRot(direction.toYRot()); -- serverLevel.addFreshEntity(abstractBoat); -- item.shrink(1); -+ if (serverLevel.addFreshEntity(abstractBoat) && shrink) item.shrink(1); // Paper - if entity add was successful and supposed to shrink + AbstractBoat boat = this.type.create(level, EntitySpawnReason.DISPENSER); + if (boat != null) { +- boat.setInitialPos(spawnX, spawnY + yOffset, spawnZ); ++ boat.setInitialPos(event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); // CraftBukkit + EntityType.createDefaultStackConfig(level, dispensed, null).accept(boat); + boat.setYRot(direction.toYRot()); +- level.addFreshEntity(boat); +- dispensed.shrink(1); ++ if (level.addFreshEntity(boat) && shrink) dispensed.shrink(1); // Paper - if entity add was successful and supposed to shrink } - return item; + return dispensed; diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch index 9007c067cefe..70a6553a3a17 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch @@ -1,60 +1,60 @@ --- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -@@ -10,24 +_,37 @@ +@@ -11,24 +_,37 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { private static final int DEFAULT_ACCURACY = 6; + private Direction direction; // Paper - cache facing direction @Override - public final ItemStack dispense(BlockSource blockSource, ItemStack item) { -+ this.direction = blockSource.state().getValue(DispenserBlock.FACING); // Paper - cache facing direction - ItemStack itemStack = this.execute(blockSource, item); - this.playSound(blockSource); -- this.playAnimation(blockSource, blockSource.state().getValue(DispenserBlock.FACING)); -+ this.playAnimation(blockSource, this.direction); // Paper - cache facing direction - return itemStack; + public final ItemStack dispense(final BlockSource source, final ItemStack dispensed) { ++ this.direction = source.state().getValue(DispenserBlock.FACING); // Paper - cache facing direction + ItemStack result = this.execute(source, dispensed); + this.playSound(source); +- this.playAnimation(source, source.state().getValue(DispenserBlock.FACING)); ++ this.playAnimation(source, this.direction); // Paper - cache facing direction + return result; } - protected ItemStack execute(BlockSource blockSource, ItemStack item) { -- Direction direction = blockSource.state().getValue(DispenserBlock.FACING); + protected ItemStack execute(final BlockSource source, final ItemStack dispensed) { +- Direction direction = source.state().getValue(DispenserBlock.FACING); + // Paper - cache facing direction - Position dispensePosition = DispenserBlock.getDispensePosition(blockSource); - ItemStack itemStack = item.split(1); -- spawnItem(blockSource.level(), itemStack, 6, direction, dispensePosition); + Position position = DispenserBlock.getDispensePosition(source); + ItemStack itemStack = dispensed.split(1); +- spawnItem(source.level(), itemStack, 6, direction, position); + // CraftBukkit start -+ if (!DefaultDispenseItemBehavior.spawnItem(blockSource.level(), itemStack, 6, this.direction, dispensePosition, blockSource)) { -+ item.grow(1); ++ if (!DefaultDispenseItemBehavior.spawnItem(source.level(), itemStack, 6, this.direction, position, source)) { ++ dispensed.grow(1); + } + // CraftBukkit end - return item; + return dispensed; } - public static void spawnItem(Level level, ItemStack stack, int speed, Direction facing, Position position) { + public static void spawnItem(final Level level, final ItemStack itemStack, final int accuracy, final Direction direction, final Position position) { + // CraftBukkit start -+ ItemEntity itemEntity = prepareItem(level, stack, speed, facing, position); ++ ItemEntity itemEntity = prepareItem(level, itemStack, accuracy, direction, position); + level.addFreshEntity(itemEntity); + } + -+ private static ItemEntity prepareItem(Level level, ItemStack stack, int speed, Direction facing, Position position) { ++ private static ItemEntity prepareItem(final Level level, final ItemStack itemStack, final int accuracy, final Direction direction, final Position position) { + // CraftBukkit end - double d = position.x(); - double d1 = position.y(); - double d2 = position.z(); -@@ -44,7 +_,43 @@ - level.random.triangle(0.2, 0.0172275 * speed), - level.random.triangle(facing.getStepZ() * d3, 0.0172275 * speed) + double spawnX = position.x(); + double spawnY = position.y(); + double spawnZ = position.z(); +@@ -46,7 +_,43 @@ + random.triangle(0.2, 0.0172275 * accuracy), + random.triangle(direction.getStepZ() * pow, 0.0172275 * accuracy) ); + return itemEntity; // CraftBukkit + } + + // CraftBukkit start - void -> boolean return -+ public static boolean spawnItem(Level level, ItemStack stack, int speed, Direction facing, Position position, BlockSource blockSource) { -+ if (stack.isEmpty()) return true; -+ ItemEntity itemEntity = DefaultDispenseItemBehavior.prepareItem(level, stack, speed, facing, position); ++ public static boolean spawnItem(Level level, ItemStack itemStack, int accuracy, Direction direction, Position position, BlockSource source) { ++ if (itemStack.isEmpty()) return true; ++ ItemEntity itemEntity = DefaultDispenseItemBehavior.prepareItem(level, itemStack, accuracy, direction, position); + -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(itemEntity.getDeltaMovement())); + level.getCraftServer().getPluginManager().callEvent(event); @@ -66,12 +66,12 @@ + itemEntity.setItem(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); + itemEntity.setDeltaMovement(org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getVelocity())); + -+ if (blockSource.state().is(net.minecraft.world.level.block.Blocks.DISPENSER) && !event.getItem().getType().equals(craftItem.getType())) { ++ if (source.state().is(net.minecraft.world.level.block.Blocks.DISPENSER) && !event.getItem().getType().equals(craftItem.getType())) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior.getClass() != DefaultDispenseItemBehavior.class) { -+ dispenseBehavior.dispense(blockSource, eventStack); ++ dispenseBehavior.dispense(source, eventStack); + } else { + level.addFreshEntity(itemEntity); + } @@ -84,4 +84,4 @@ + // CraftBukkit end } - protected void playSound(BlockSource blockSource) { + protected void playSound(final BlockSource source) { diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch index ba660f85657e..c20e62bd1f11 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch @@ -1,20 +1,19 @@ --- a/net/minecraft/core/dispenser/DispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -88,10 +_,38 @@ - if (type == null) { - return item; - } else { +@@ -86,12 +_,38 @@ + Direction direction = source.state().getValue(DispenserBlock.FACING); + BlockPos pos = source.pos().relative(direction); + ServerLevel serverLevel = source.level(); + // CraftBukkit start -+ ServerLevel serverLevel = blockSource.level(); -+ ItemStack singleItemStack = item.copyWithCount(1); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); ++ ItemStack singleItemStack = dispensed.copyWithCount(1); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, source.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); + serverLevel.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -22,93 +21,42 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; -+ } -+ // Paper start - track changed items in the dispense event -+ singleItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified -+ type = ((SpawnEggItem) singleItemStack.getItem()).getType(singleItemStack); -+ // Paper end - track changed item from dispense event -+ } - try { - type.spawn( - blockSource.level(), -- item, -+ singleItemStack, // Paper - track changed item in dispense event - null, - blockSource.pos().relative(direction), - EntitySpawnReason.DISPENSER, -@@ -103,7 +_,8 @@ - return ItemStack.EMPTY; - } - -- item.shrink(1); -+ if (shrink) item.shrink(1); -+ // CraftBukkit end - blockSource.level().gameEvent(null, GameEvent.ENTITY_PLACE, blockSource.pos()); - return item; - } -@@ -122,12 +_,38 @@ - Direction direction = blockSource.state().getValue(DispenserBlock.FACING); - BlockPos blockPos = blockSource.pos().relative(direction); - ServerLevel serverLevel = blockSource.level(); -+ // CraftBukkit start -+ ItemStack singleItemStack = item.copyWithCount(1); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); -+ -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { -+ return item; -+ } -+ -+ boolean shrink = true; -+ if (!event.getItem().equals(craftItem)) { -+ shrink = false; -+ // Chain to handler for new item -+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); -+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + // CraftBukkit end + + final ItemStack newStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified) - Consumer consumer = EntityType.appendDefaultStackConfig( -- armorStand1 -> armorStand1.setYRot(direction.toYRot()), serverLevel, item, null -+ armorStand1 -> armorStand1.setYRot(direction.toYRot()), serverLevel, newStack, null // Paper - track changed items in the dispense event + Consumer postSpawnConfig = EntityType.appendDefaultStackConfig( +- armorStandx -> armorStandx.setYRot(direction.toYRot()), serverLevel, dispensed, null ++ armorStandx -> armorStandx.setYRot(direction.toYRot()), serverLevel, newStack, null // Paper - track changed items in the dispense event ); - ArmorStand armorStand = EntityType.ARMOR_STAND.spawn(serverLevel, consumer, blockPos, EntitySpawnReason.DISPENSER, false, false); + ArmorStand armorStand = EntityType.ARMOR_STAND.spawn(serverLevel, postSpawnConfig, pos, EntitySpawnReason.DISPENSER, false, false); if (armorStand != null) { -- item.shrink(1); -+ if (shrink) item.shrink(1); // Paper +- dispensed.shrink(1); ++ if (shrink) dispensed.shrink(1); // Paper } - return item; -@@ -149,8 +_,35 @@ - )) { + return dispensed; +@@ -109,8 +_,33 @@ + .getEntitiesOfClass(AbstractChestedHorse.class, new AABB(pos), entity -> entity.isAlive() && !entity.hasChest())) { if (abstractChestedHorse.isTamed()) { SlotAccess slot = abstractChestedHorse.getSlot(499); -- if (slot != null && slot.set(item)) { -- item.shrink(1); +- if (slot != null && slot.set(dispensed)) { +- dispensed.shrink(1); + // CraftBukkit start -+ if (slot != null/* && slot.set(item)*/) { -+ ItemStack singleCopy = item.copyWithCount(1); -+ ServerLevel world = blockSource.level(); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos()); ++ if (slot != null/* && slot.set(dispensed)*/) { ++ ItemStack singleCopy = dispensed.copyWithCount(1); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleCopy); + org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), abstractChestedHorse.getBukkitLivingEntity()); -+ world.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { ++ if (!event.callEvent()) { + this.setSuccess(false); -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -116,140 +64,138 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + slot.set(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); + // CraftBukkit end + -+ if (shrink) item.shrink(1); // Paper - actually handle here ++ if (shrink) dispensed.shrink(1); // Paper - actually handle here this.setSuccess(true); - return item; + return dispensed; } -@@ -189,8 +_,45 @@ - DispensibleContainerItem dispensibleContainerItem = (DispensibleContainerItem)item.getItem(); - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); - Level level = blockSource.level(); +@@ -149,8 +_,45 @@ + DispensibleContainerItem bucket = (DispensibleContainerItem)dispensed.getItem(); + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + Level level = source.level(); + // CraftBukkit start -+ BlockState state = level.getBlockState(blockPos); -+ ItemStack dispensedItem = item; // Paper - track changed item from the dispense event ++ BlockState state = level.getBlockState(target); ++ ItemStack dispensedItem = dispensed; // Paper - track changed item from the dispense event + // Paper start - correctly check if the bucket place will succeed + /* Taken from SolidBucketItem#emptyContents */ -+ boolean willEmptyContentsSolidBucketItem = dispensibleContainerItem instanceof net.minecraft.world.item.SolidBucketItem && level.isInWorldBounds(blockPos) && state.isAir(); ++ boolean willEmptyContentsSolidBucketItem = bucket instanceof net.minecraft.world.item.SolidBucketItem && level.isInWorldBounds(target) && state.isAir(); + /* Taken from BucketItem#emptyContents */ -+ boolean willEmptyBucketItem = dispensibleContainerItem instanceof final net.minecraft.world.item.BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (state.isAir() || state.canBeReplaced(bucketItem.content) || (state.getBlock() instanceof net.minecraft.world.level.block.LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, level, blockPos, state, bucketItem.content))); ++ boolean willEmptyBucketItem = bucket instanceof final net.minecraft.world.item.BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (state.isAir() || state.canBeReplaced(bucketItem.content) || (state.getBlock() instanceof net.minecraft.world.level.block.LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, level, target, state, bucketItem.content))); + if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) { + // Paper end - correctly check if the bucket place will succeed -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed.copyWithCount(1)); // Paper - single item in event + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(target)); + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + + // Paper start - track changed item from dispense event + dispensedItem = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated -+ dispensibleContainerItem = (DispensibleContainerItem) dispensedItem.getItem(); ++ bucket = (DispensibleContainerItem)dispensedItem.getItem(); + // Paper end - track changed item from dispense event + } + // CraftBukkit end + - if (dispensibleContainerItem.emptyContents(null, level, blockPos, null)) { -- dispensibleContainerItem.checkExtraContent(null, level, item, blockPos); -+ dispensibleContainerItem.checkExtraContent(null, level, dispensedItem, blockPos); // Paper - track changed item from dispense event - return this.consumeWithRemainder(blockSource, item, new ItemStack(Items.BUCKET)); + if (bucket.emptyContents(null, level, target, null)) { +- bucket.checkExtraContent(null, level, dispensed, target); ++ bucket.checkExtraContent(null, level, dispensedItem, target); // Paper - track changed item from dispense event + return this.consumeWithRemainder(source, dispensed, new ItemStack(Items.BUCKET)); } else { - return this.defaultDispenseItemBehavior.dispense(blockSource, item); -@@ -213,12 +_,19 @@ - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); - BlockState blockState = levelAccessor.getBlockState(blockPos); - if (blockState.getBlock() instanceof BucketPickup bucketPickup) { -- ItemStack itemStack = bucketPickup.pickupBlock(null, levelAccessor, blockPos, blockState); -+ ItemStack itemStack = bucketPickup.pickupBlock(null, org.bukkit.craftbukkit.util.DummyGeneratorAccess.INSTANCE, blockPos, blockState); // CraftBukkit - if (itemStack.isEmpty()) { - return super.execute(blockSource, item); + return this.defaultDispenseItemBehavior.dispense(source, dispensed); +@@ -173,12 +_,19 @@ + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + BlockState blockState = level.getBlockState(target); + if (blockState.getBlock() instanceof BucketPickup bucket) { +- ItemStack pickup = bucket.pickupBlock(null, level, target, blockState); ++ ItemStack pickup = bucket.pickupBlock(null, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, target, blockState); // CraftBukkit + if (pickup.isEmpty()) { + return super.execute(source, dispensed); } else { - levelAccessor.gameEvent(null, GameEvent.FLUID_PICKUP, blockPos); - Item item1 = itemStack.getItem(); + level.gameEvent(null, GameEvent.FLUID_PICKUP, target); + Item targetType = pickup.getItem(); + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + return result; + } + // Paper end - Call BlockDispenseEvent -+ itemStack = bucketPickup.pickupBlock(null, levelAccessor, blockPos, blockState); // CraftBukkit - from above - return this.consumeWithRemainder(blockSource, item, new ItemStack(item1)); ++ pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above + return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType)); } } else { -@@ -233,15 +_,26 @@ +@@ -193,15 +_,26 @@ this.setSuccess(true); - Direction direction = blockSource.state().getValue(DispenserBlock.FACING); - BlockPos blockPos = blockSource.pos().relative(direction); + Direction facing = source.state().getValue(DispenserBlock.FACING); + BlockPos targetPos = source.pos().relative(facing); + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent - BlockState blockState = serverLevel.getBlockState(blockPos); - if (BaseFireBlock.canBePlacedAt(serverLevel, blockPos, direction)) { -- serverLevel.setBlockAndUpdate(blockPos, BaseFireBlock.getState(serverLevel, blockPos)); -- serverLevel.gameEvent(null, GameEvent.BLOCK_PLACE, blockPos); + BlockState target = level.getBlockState(targetPos); + if (BaseFireBlock.canBePlacedAt(level, targetPos, facing)) { + // CraftBukkit start - Ignition by dispensing flint and steel -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(serverLevel, blockPos, blockSource.pos()).isCancelled()) { -+ serverLevel.setBlockAndUpdate(blockPos, BaseFireBlock.getState(serverLevel, blockPos)); -+ serverLevel.gameEvent(null, GameEvent.BLOCK_PLACE, blockPos); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, targetPos, source.pos()).isCancelled()) { + level.setBlockAndUpdate(targetPos, BaseFireBlock.getState(level, targetPos)); + level.gameEvent(null, GameEvent.BLOCK_PLACE, targetPos); + } + // CraftBukkit end - } else if (CampfireBlock.canLight(blockState) || CandleBlock.canLight(blockState) || CandleCakeBlock.canLight(blockState)) { - serverLevel.setBlockAndUpdate(blockPos, blockState.setValue(BlockStateProperties.LIT, true)); - serverLevel.gameEvent(null, GameEvent.BLOCK_CHANGE, blockPos); - } else if (blockState.getBlock() instanceof TntBlock) { -- if (TntBlock.prime(serverLevel, blockPos)) { -+ if (TntBlock.prime(serverLevel, blockPos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(serverLevel, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, blockSource.pos()))) { // CraftBukkit - TNTPrimeEvent - serverLevel.removeBlock(blockPos, false); + } else if (CampfireBlock.canLight(target) || CandleBlock.canLight(target) || CandleCakeBlock.canLight(target)) { + level.setBlockAndUpdate(targetPos, target.setValue(BlockStateProperties.LIT, true)); + level.gameEvent(null, GameEvent.BLOCK_CHANGE, targetPos); + } else if (target.getBlock() instanceof TntBlock) { +- if (TntBlock.prime(level, targetPos)) { ++ if (TntBlock.prime(level, targetPos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, targetPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, source.pos()))) { // CraftBukkit - TNTPrimeEvent + level.removeBlock(targetPos, false); } else { this.setSuccess(false); -@@ -263,11 +_,46 @@ +@@ -223,11 +_,46 @@ this.setSuccess(true); - Level level = blockSource.level(); - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); + Level level = source.level(); + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent + level.captureTreeGeneration = true; // CraftBukkit - if (!BoneMealItem.growCrop(item, level, blockPos) && !BoneMealItem.growWaterPlant(item, level, blockPos, null)) { + if (!BoneMealItem.growCrop(dispensed, level, target) && !BoneMealItem.growWaterPlant(dispensed, level, target, null)) { this.setSuccess(false); } else if (!level.isClientSide()) { - level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, blockPos, 15); + level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, target, 15); } + // CraftBukkit start + level.captureTreeGeneration = false; + if (!level.capturedBlockStates.isEmpty()) { + org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; + net.minecraft.world.level.block.SaplingBlock.treeType = null; -+ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level); ++ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(target, level); + List states = new java.util.ArrayList<>(level.capturedBlockStates.values()); + level.capturedBlockStates.clear(); + org.bukkit.event.world.StructureGrowEvent structureEvent = null; @@ -266,29 +212,29 @@ + for (org.bukkit.block.BlockState state : states) { + org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) state; + craftBlockState.place(craftBlockState.getFlags()); -+ blockSource.level().checkCapturedTreeStateForObserverNotify(blockPos, craftBlockState); // Paper - notify observers even if grow failed ++ source.level().checkCapturedTreeStateForObserverNotify(target, craftBlockState); // Paper - notify observers even if grow failed + } + } + } + // CraftBukkit end - return item; + return dispensed; } -@@ -281,11 +_,36 @@ - return item; +@@ -241,11 +_,36 @@ + return dispensed; } else { - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); -- PrimedTnt primedTnt = new PrimedTnt(serverLevel, blockPos.getX() + 0.5, blockPos.getY(), blockPos.getZ() + 0.5, null); + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); +- PrimedTnt tnt = new PrimedTnt(level, target.getX() + 0.5, target.getY(), target.getZ() + 0.5, null); + // CraftBukkit start -+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink at end and single item in event -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); ++ ItemStack singleItemStack = dispensed.copyWithCount(1); // Paper - shrink at end and single item in event ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D)); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) target.getX() + 0.5D, (double) target.getY(), (double) target.getZ() + 0.5D)); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -296,150 +242,150 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + -+ PrimedTnt primedTnt = new PrimedTnt(serverLevel, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), null); ++ PrimedTnt tnt = new PrimedTnt(level, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), null); + // CraftBukkit end - serverLevel.addFreshEntity(primedTnt); - serverLevel.playSound(null, primedTnt.getX(), primedTnt.getY(), primedTnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); -- serverLevel.gameEvent(null, GameEvent.ENTITY_PLACE, blockPos); -- item.shrink(1); -+ serverLevel.gameEvent(null, GameEvent.ENTITY_PLACE, org.bukkit.craftbukkit.util.CraftVector.toBlockPos(event.getVelocity())); // Paper - update game event position -+ if (shrink) item.shrink(1); // Paper + level.addFreshEntity(tnt); + level.playSound(null, tnt.getX(), tnt.getY(), tnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); +- level.gameEvent(null, GameEvent.ENTITY_PLACE, target); +- dispensed.shrink(1); ++ level.gameEvent(null, GameEvent.ENTITY_PLACE, org.bukkit.craftbukkit.util.CraftVector.toBlockPos(event.getVelocity())); // Paper - update game event position ++ if (shrink) dispensed.shrink(1); // Paper this.setSuccess(true); - return item; + return dispensed; } -@@ -299,6 +_,13 @@ - Level level = blockSource.level(); - Direction direction = blockSource.state().getValue(DispenserBlock.FACING); - BlockPos blockPos = blockSource.pos().relative(direction); +@@ -259,6 +_,13 @@ + Level level = source.level(); + Direction direction = source.state().getValue(DispenserBlock.FACING); + BlockPos target = source.pos().relative(direction); + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent - if (level.isEmptyBlock(blockPos) && WitherSkullBlock.canSpawnMob(level, blockPos, item)) { + if (level.isEmptyBlock(target) && WitherSkullBlock.canSpawnMob(level, target, dispensed)) { level.setBlock( - blockPos, -@@ -314,7 +_,7 @@ - item.shrink(1); + target, +@@ -274,7 +_,7 @@ + dispensed.shrink(1); this.setSuccess(true); } else { -- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(blockSource, item)); -+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(blockSource, item, this)); // Paper - fix possible StackOverflowError +- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(source, dispensed)); ++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(source, dispensed, this)); // Paper - fix possible StackOverflowError } - return item; -@@ -327,6 +_,13 @@ - Level level = blockSource.level(); - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); - CarvedPumpkinBlock carvedPumpkinBlock = (CarvedPumpkinBlock)Blocks.CARVED_PUMPKIN; + return dispensed; +@@ -287,6 +_,13 @@ + Level level = source.level(); + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + CarvedPumpkinBlock pumpkinBlock = (CarvedPumpkinBlock)Blocks.CARVED_PUMPKIN; + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent - if (level.isEmptyBlock(blockPos) && carvedPumpkinBlock.canSpawnGolem(level, blockPos)) { + if (level.isEmptyBlock(target) && pumpkinBlock.canSpawnGolem(level, target)) { if (!level.isClientSide()) { - level.setBlock(blockPos, carvedPumpkinBlock.defaultBlockState(), Block.UPDATE_ALL); -@@ -336,7 +_,7 @@ - item.shrink(1); + level.setBlock(target, pumpkinBlock.defaultBlockState(), Block.UPDATE_ALL); +@@ -296,7 +_,7 @@ + dispensed.shrink(1); this.setSuccess(true); } else { -- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(blockSource, item)); -+ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(blockSource, item, this)); // Paper - fix possible StackOverflowError +- this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(source, dispensed)); ++ this.setSuccess(EquipmentDispenseItemBehavior.dispenseEquipment(source, dispensed, this)); // Paper - fix possible StackOverflowError } - return item; -@@ -362,6 +_,12 @@ - ServerLevel serverLevel = blockSource.level(); - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); - BlockState blockState = serverLevel.getBlockState(blockPos); + return dispensed; +@@ -334,6 +_,12 @@ + ServerLevel level = source.level(); + BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + BlockState state = level.getBlockState(target); + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + return result; + } + // Paper end - Call BlockDispenseEvent - if (blockState.is( - BlockTags.BEEHIVES, - blockStateBase -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockStateBase.getBlock() instanceof BeehiveBlock -@@ -390,6 +_,13 @@ + if (state.is(BlockTags.BEEHIVES, s -> s.hasProperty(BeehiveBlock.HONEY_LEVEL) && s.getBlock() instanceof BeehiveBlock) + && state.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) { + ((BeehiveBlock)state.getBlock()) +@@ -359,6 +_,13 @@ this.setSuccess(true); if (blockState.is(Blocks.RESPAWN_ANCHOR)) { if (blockState.getValue(RespawnAnchorBlock.CHARGE) != 4) { + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, pos, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent - RespawnAnchorBlock.charge(null, level, blockPos, blockState); - item.shrink(1); + RespawnAnchorBlock.charge(null, level, pos, blockState); + dispensed.shrink(1); } else { -@@ -413,6 +_,28 @@ +@@ -382,6 +_,28 @@ this.setSuccess(false); - return item; + return dispensed; } else { + // CraftBukkit start -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity()); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), armadillos.get(0).getBukkitLivingEntity()); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + this.setSuccess(false); -+ return item; ++ return dispensed; + } + + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + // CraftBukkit end - for (Armadillo armadillo : entitiesOfClass) { - if (armadillo.brushOffScute(null, item)) { - item.hurtAndBreak(16, serverLevel, null, item1 -> {}); -@@ -433,6 +_,13 @@ - BlockState blockState = level.getBlockState(blockPos); - Optional waxed = HoneycombItem.getWaxed(blockState); - if (waxed.isPresent()) { + for (Armadillo armadillo : armadillos) { + if (armadillo.brushOffScute(null, dispensed)) { + dispensed.hurtAndBreak(16, level, null, item -> {}); +@@ -402,6 +_,13 @@ + BlockState blockState = level.getBlockState(pos); + Optional maybeWaxed = HoneycombItem.getWaxed(blockState); + if (maybeWaxed.isPresent()) { + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, pos, dispensed, this); + if (result != null) { + this.setSuccess(false); + return result; + } + // Paper end - Call BlockDispenseEvent - level.setBlockAndUpdate(blockPos, waxed.get()); - level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_WAX_ON, blockPos, 0); - item.shrink(1); -@@ -460,6 +_,12 @@ - if (!serverLevel.getBlockState(blockPos1).is(BlockTags.CONVERTABLE_TO_MUD)) { - return this.defaultDispenseItemBehavior.dispense(blockSource, item); + level.setBlockAndUpdate(pos, maybeWaxed.get()); + level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_WAX_ON, pos, 0); + dispensed.shrink(1); +@@ -429,6 +_,12 @@ + if (!level.getBlockState(target).is(BlockTags.CONVERTABLE_TO_MUD)) { + return this.defaultDispenseItemBehavior.dispense(source, dispensed); } else { + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos1, item, this); ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + return result; + } + // Paper end - Call BlockDispenseEvent - if (!serverLevel.isClientSide()) { - for (int i = 0; i < 5; i++) { - serverLevel.sendParticles( + if (!level.isClientSide()) { + RandomSource random = level.getRandom(); + diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch index bf7562248686..fd59898eb292 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch @@ -3,35 +3,35 @@ @@ -14,10 +_,17 @@ @Override - protected ItemStack execute(BlockSource blockSource, ItemStack item) { -- return dispenseEquipment(blockSource, item) ? item : super.execute(blockSource, item); -+ return dispenseEquipment(blockSource, item, this) ? item : super.execute(blockSource, item); // Paper - fix possible StackOverflowError + protected ItemStack execute(final BlockSource source, final ItemStack dispensed) { +- return dispenseEquipment(source, dispensed) ? dispensed : super.execute(source, dispensed); ++ return dispenseEquipment(source, dispensed, this) ? dispensed : super.execute(source, dispensed); // Paper - fix possible StackOverflowError } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - public static boolean dispenseEquipment(BlockSource blockSource, ItemStack item) { + public static boolean dispenseEquipment(final BlockSource source, final ItemStack dispensed) { + // Paper start -+ return dispenseEquipment(blockSource, item, null); ++ return dispenseEquipment(source, dispensed, null); + } + -+ public static boolean dispenseEquipment(BlockSource blockSource, ItemStack item, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) { ++ public static boolean dispenseEquipment(final BlockSource source, final ItemStack dispensed, final @org.jspecify.annotations.Nullable DispenseItemBehavior currentBehavior) { + // Paper end - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); - List entitiesOfClass = blockSource.level() - .getEntitiesOfClass(LivingEntity.class, new AABB(blockPos), entity -> entity.canEquipWithDispenser(item)); -@@ -26,13 +_,39 @@ + BlockPos pos = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); + List entities = source.level().getEntitiesOfClass(LivingEntity.class, new AABB(pos), entity -> entity.canEquipWithDispenser(dispensed)); + if (entities.isEmpty()) { +@@ -25,13 +_,39 @@ } else { - LivingEntity livingEntity = entitiesOfClass.getFirst(); - EquipmentSlot equipmentSlotForItem = livingEntity.getEquipmentSlotForItem(item); -- ItemStack itemStack = item.split(1); -- livingEntity.setItemSlot(equipmentSlotForItem, itemStack); -+ ItemStack itemStack = item.copyWithCount(1); // Paper - shrink below and single item in event + LivingEntity target = entities.getFirst(); + EquipmentSlot slot = target.getEquipmentSlotForItem(dispensed); +- ItemStack equip = dispensed.split(1); +- target.setItemSlot(slot, equip); ++ ItemStack equip = dispensed.copyWithCount(1); // Paper - shrink below and single item in event + // CraftBukkit start -+ net.minecraft.world.level.Level world = blockSource.level(); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); ++ net.minecraft.world.level.Level world = source.level(); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(equip); + -+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) livingEntity.getBukkitEntity()); ++ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity()); + world.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { @@ -43,21 +43,21 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) { -+ dispenseItemBehavior.dispense(blockSource, eventStack); ++ dispenseItemBehavior.dispense(source, eventStack); + return true; + } + } + -+ livingEntity.setItemSlot(equipmentSlotForItem, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); ++ target.setItemSlot(slot, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); + // CraftBukkit end - if (livingEntity instanceof Mob mob) { - mob.setGuaranteedDrop(equipmentSlotForItem); - mob.setPersistenceRequired(); + if (target instanceof Mob targetMob) { + targetMob.setGuaranteedDrop(slot); + targetMob.setPersistenceRequired(); } -+ if (shrink) item.shrink(1); // Paper - shrink here ++ if (shrink) dispensed.shrink(1); // Paper - shrink here return true; } } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java.patch index 0acafa1f5ab3..f3a2e22b82ba 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java.patch @@ -1,21 +1,19 @@ --- a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -@@ -58,12 +_,35 @@ +@@ -58,12 +_,37 @@ } - Vec3 vec31 = new Vec3(d, d1 + d3, d2); -- AbstractMinecart abstractMinecart = AbstractMinecart.createMinecart( -- serverLevel, vec31.x, vec31.y, vec31.z, this.entityType, EntitySpawnReason.DISPENSER, item, null -- ); -+ ItemStack itemstack1 = item.copyWithCount(1); // Paper - shrink below and single item in event -+ org.bukkit.block.Block block2 = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1); + Vec3 spawnPos = new Vec3(spawnX, spawnY + yOffset, spawnZ); ++ // CraftBukkit start ++ ItemStack singleItemStack = dispensed.copyWithCount(1); // Paper - shrink below and single item in event ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(vec31)); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(spawnPos)); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -23,21 +21,23 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); -+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && dispenseItemBehavior != this) { -+ dispenseItemBehavior.dispense(blockSource, eventStack); -+ return item; ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); ++ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + -+ itemstack1 = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ AbstractMinecart abstractMinecart = AbstractMinecart.createMinecart(serverLevel, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.entityType, EntitySpawnReason.DISPENSER, itemstack1, null); -+ - if (abstractMinecart != null) { -- serverLevel.addFreshEntity(abstractMinecart); -- item.shrink(1); -+ if (serverLevel.addFreshEntity(abstractMinecart) && shrink) item.shrink(1); // Paper - if entity add was successful and supposed to shrink ++ singleItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); + AbstractMinecart minecart = AbstractMinecart.createMinecart( +- level, spawnPos.x, spawnPos.y, spawnPos.z, this.entityType, EntitySpawnReason.DISPENSER, dispensed, null ++ level, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.entityType, EntitySpawnReason.DISPENSER, singleItemStack, null + ); + if (minecart != null) { +- level.addFreshEntity(minecart); +- dispensed.shrink(1); ++ if (level.addFreshEntity(minecart) && shrink) dispensed.shrink(1); // Paper - if entity add was successful and supposed to shrink + // CraftBukkit end } - return item; + return dispensed; diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch index 3fa36c36dfd4..772e836788a4 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java @@ -27,17 +_,36 @@ - ServerLevel serverLevel = blockSource.level(); - Direction direction = blockSource.state().getValue(DispenserBlock.FACING); - Position dispensePosition = this.dispenseConfig.positionFunction().getDispensePosition(blockSource, direction); + ServerLevel level = source.level(); + Direction direction = source.state().getValue(DispenserBlock.FACING); + Position position = this.dispenseConfig.positionFunction().getDispensePosition(source, direction); - Projectile.spawnProjectileUsingShoot( -- this.projectileItem.asProjectile(serverLevel, dispensePosition, item, direction), -- serverLevel, -- item, +- this.projectileItem.asProjectile(level, position, dispensed, direction), +- level, +- dispensed, - direction.getStepX(), - direction.getStepY(), - direction.getStepZ(), - this.dispenseConfig.power(), - this.dispenseConfig.uncertainty() - ); -- item.shrink(1); -+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); +- dispensed.shrink(1); ++ ItemStack singleItemStack = dispensed.copyWithCount(1); // Paper - shrink below and single item in event ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(direction.getStepX(), direction.getStepY(), direction.getStepZ())); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + boolean shrink = true; @@ -31,20 +31,20 @@ + shrink = false; + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + + // SPIGOT-7923: Avoid create projectiles with empty item + if (!singleItemStack.isEmpty()) { -+ Projectile projectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(serverLevel, dispensePosition, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), serverLevel, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies -+ projectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(blockSource.blockEntity()); ++ Projectile projectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(level, position, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), level, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies ++ projectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(source.blockEntity()); + } -+ if (shrink) item.shrink(1); ++ if (shrink) dispensed.shrink(1); + // CraftBukkit end - return item; + return dispensed; } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java.patch index 4d6ce2c36aca..e33af392147a 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java.patch @@ -2,58 +2,58 @@ +++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java @@ -20,9 +_,30 @@ @Override - protected ItemStack execute(BlockSource blockSource, ItemStack item) { - ServerLevel serverLevel = blockSource.level(); + protected ItemStack execute(final BlockSource source, final ItemStack dispensed) { + ServerLevel level = source.level(); + // CraftBukkit start -+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items ++ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); -+ serverLevel.getCraftServer().getPluginManager().callEvent(event); ++ level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + this.setSuccess(false); -+ return item; ++ return dispensed; + } + + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + // CraftBukkit end - if (!serverLevel.isClientSide()) { - BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); -- this.setSuccess(tryShearBeehive(serverLevel, item, blockPos) || tryShearEntity(serverLevel, blockPos, item)); -+ this.setSuccess(tryShearBeehive(serverLevel, item, blockPos) || tryShearEntity(serverLevel, blockPos, item, bukkitBlock, craftItem)); // CraftBukkit + if (!level.isClientSide()) { + BlockPos pos = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); +- this.setSuccess(tryShearBeehive(level, dispensed, pos) || tryShearEntity(level, pos, dispensed)); ++ this.setSuccess(tryShearBeehive(level, dispensed, pos) || tryShearEntity(level, pos, dispensed, bukkitBlock, craftItem)); // CraftBukkit if (this.isSuccess()) { - item.hurtAndBreak(1, serverLevel, null, item1 -> {}); + dispensed.hurtAndBreak(1, level, null, item -> {}); } -@@ -50,14 +_,22 @@ +@@ -47,14 +_,22 @@ return false; } -- private static boolean tryShearEntity(ServerLevel level, BlockPos pos, ItemStack stack) { -+ private static boolean tryShearEntity(ServerLevel level, BlockPos pos, ItemStack stack, org.bukkit.block.Block bukkitBlock, org.bukkit.craftbukkit.inventory.CraftItemStack craftItem) { // CraftBukkit - add args +- private static boolean tryShearEntity(final ServerLevel level, final BlockPos pos, final ItemStack tool) { ++ private static boolean tryShearEntity(final ServerLevel level, final BlockPos pos, final ItemStack tool, org.bukkit.block.Block bukkitBlock, org.bukkit.craftbukkit.inventory.CraftItemStack craftItem) { // CraftBukkit - add args for (Entity entity : level.getEntitiesOfClass(Entity.class, new AABB(pos), EntitySelector.NO_SPECTATORS)) { if (entity.shearOffAllLeashConnections(null)) { return true; } if (entity instanceof Shearable shearable && shearable.readyForShearing()) { -- shearable.shear(level, SoundSource.BLOCKS, stack); +- shearable.shear(level, SoundSource.BLOCKS, tool); + // CraftBukkit start + // Paper start - Add drops to shear events -+ org.bukkit.event.block.BlockShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockShearEntityEvent(entity, bukkitBlock, craftItem, shearable.generateDefaultDrops(level, stack)); ++ org.bukkit.event.block.BlockShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockShearEntityEvent(entity, bukkitBlock, craftItem, shearable.generateDefaultDrops(level, tool)); + if (event.isCancelled()) { + // Paper end - Add drops to shear events + continue; + } + // CraftBukkit end -+ shearable.shear(level, SoundSource.BLOCKS, stack, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops())); // Paper - Add drops to shear events ++ shearable.shear(level, SoundSource.BLOCKS, tool, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops())); // Paper - Add drops to shear events level.gameEvent(null, GameEvent.SHEAR, pos); return true; } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch index 06c88a18571c..acc9e4c90c27 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch @@ -1,40 +1,40 @@ --- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java @@ -22,10 +_,36 @@ - BlockPos blockPos = blockSource.pos().relative(direction); - Direction direction1 = blockSource.level().isEmptyBlock(blockPos.below()) ? direction : Direction.UP; + BlockPos relativePos = source.pos().relative(facing); + Direction clickedFace = source.level().isEmptyBlock(relativePos.below()) ? facing : Direction.UP; + // CraftBukkit start -+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(blockSource.level(), blockSource.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); ++ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed.copyWithCount(1)); + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); -+ blockSource.level().getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(relativePos)); ++ source.level().getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { -+ return item; ++ return dispensed; + } + + if (!event.getItem().equals(craftItem)) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); + if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(blockSource, eventStack); -+ return item; ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } + } + // CraftBukkit end try { + // Paper start - track changed items in the dispense event this.setSuccess( -- ((BlockItem)item1).place(new DirectionalPlaceContext(blockSource.level(), blockPos, direction, item, direction1)).consumesAction() -+ ((BlockItem) item1).place(new DirectionalPlaceContext(blockSource.level(), blockPos, direction, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction1)).consumesAction() +- ((BlockItem)item).place(new DirectionalPlaceContext(source.level(), relativePos, facing, dispensed, clickedFace)).consumesAction() ++ ((BlockItem)item).place(new DirectionalPlaceContext(source.level(), relativePos, facing, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), clickedFace)).consumesAction() ); + if (this.isSuccess()) { -+ item.shrink(1); // vanilla shrink is in the place function above, manually handle it here ++ dispensed.shrink(1); // vanilla shrink is in the place function above, manually handle it here + } + // Paper end - track changed items in the dispense event } catch (Exception var8) { - LOGGER.error("Error trying to place shulker box at {}", blockPos, var8); + LOGGER.error("Error trying to place shulker box at {}", relativePos, var8); } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch new file mode 100644 index 000000000000..026114b948d0 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch @@ -0,0 +1,42 @@ +--- a/net/minecraft/core/dispenser/SpawnEggItemBehavior.java ++++ b/net/minecraft/core/dispenser/SpawnEggItemBehavior.java +@@ -18,14 +_,37 @@ + if (type == null) { + return dispensed; + } else { ++ // Paper start - block dispense event ++ ItemStack singleDispensed = dispensed.copyWithCount(1); ++ final org.bukkit.craftbukkit.inventory.CraftItemStack eventItemCopy = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleDispensed); ++ final org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()), ++ eventItemCopy, ++ new org.bukkit.util.Vector(0, 0, 0) ++ ); ++ if (!event.callEvent()) return dispensed; ++ ++ final boolean shrink = event.getItem().equals(eventItemCopy); ++ if (!shrink) { ++ final ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); ++ final DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); ++ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; ++ } ++ ++ type = SpawnEggItem.getType(eventStack); ++ singleDispensed = eventStack; ++ } ++ // Paper end - block dispense event + try { +- type.spawn(source.level(), dispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); ++ type.spawn(source.level(), singleDispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); // Paper - block dispense event - update used item stack + } catch (Exception var6) { + LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), var6); + return ItemStack.EMPTY; + } + +- dispensed.shrink(1); ++ if (shrink) dispensed.shrink(1); // Paper - block dispense event - only shrink if above logic requires it. + source.level().gameEvent(null, GameEvent.ENTITY_PLACE, source.pos()); + return dispensed; + } diff --git a/paper-server/patches/sources/net/minecraft/core/particles/SpellParticleOption.java.patch b/paper-server/patches/sources/net/minecraft/core/particles/SpellParticleOption.java.patch index 03e72654547c..db4e1c2f2e8c 100644 --- a/paper-server/patches/sources/net/minecraft/core/particles/SpellParticleOption.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/particles/SpellParticleOption.java.patch @@ -8,4 +8,4 @@ + public final int color; // Paper - public private final float power; - public static MapCodec codec(ParticleType type) { + public static MapCodec codec(final ParticleType type) { diff --git a/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch b/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch index 83c57bdfd6a3..a1540c1aa6c5 100644 --- a/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/registries/BuiltInRegistries.java +++ b/net/minecraft/core/registries/BuiltInRegistries.java -@@ -356,6 +_,11 @@ +@@ -361,6 +_,11 @@ public static final Registry> SLOT_SOURCE_TYPE = registerSimple(Registries.SLOT_SOURCE_TYPE, SlotSources::bootstrap); public static final Registry> TEST_FUNCTION = registerSimple(Registries.TEST_FUNCTION, BuiltinTestFunctions::bootstrap); public static final Registry> REGISTRY = WRITABLE_REGISTRY; @@ -10,17 +10,17 @@ + ); + // Paper end - add built-in registry conversions - private static Registry registerSimple(ResourceKey> registryKey, BuiltInRegistries.RegistryBootstrap bootstrap) { - return internalRegister(registryKey, new MappedRegistry<>(registryKey, Lifecycle.stable(), false), bootstrap); -@@ -383,6 +_,7 @@ - ResourceKey> registryKey, R registry, BuiltInRegistries.RegistryBootstrap bootstrap + private static Registry registerSimple(final ResourceKey> name, final BuiltInRegistries.RegistryBootstrap loader) { + return internalRegister(name, new MappedRegistry<>(name, Lifecycle.stable(), false), loader); +@@ -388,6 +_,7 @@ + final ResourceKey> name, final R registry, final BuiltInRegistries.RegistryBootstrap loader ) { - Bootstrap.checkBootstrapCalled(() -> "registry " + registryKey.identifier()); + Bootstrap.checkBootstrapCalled(() -> "registry " + name.identifier()); + io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry); // Paper - initialize API registry - Identifier identifier = registryKey.identifier(); - LOADERS.put(identifier, () -> bootstrap.run(registry)); - WRITABLE_REGISTRY.register((ResourceKey)registryKey, registry, RegistrationInfo.BUILT_IN); -@@ -390,16 +_,34 @@ + Identifier key = name.identifier(); + LOADERS.put(key, () -> loader.run(registry)); + WRITABLE_REGISTRY.register((ResourceKey)name, registry, RegistrationInfo.BUILT_IN); +@@ -395,16 +_,34 @@ } public static void bootStrap() { @@ -47,15 +47,15 @@ + throw new RuntimeException(ex); + } + // Paper end - class-load org.bukkit.Registry - LOADERS.forEach((identifier, supplier) -> { - if (supplier.get() == null) { - LOGGER.error("Unable to bootstrap registry '{}'", identifier); + LOADERS.forEach((key, value) -> { + if (value.get() == null) { + LOGGER.error("Unable to bootstrap registry '{}'", key); } -+ io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(ResourceKey.createRegistryKey(identifier)); // Paper - lock reference holder creation ++ io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(ResourceKey.createRegistryKey(key)); // Paper - lock reference holder creation }); } -@@ -408,6 +_,7 @@ +@@ -413,6 +_,7 @@ for (Registry registry : REGISTRY) { bindBootstrappedTagsToEmpty(registry); diff --git a/paper-server/patches/sources/net/minecraft/data/loot/packs/VanillaChestLoot.java.patch b/paper-server/patches/sources/net/minecraft/data/loot/packs/VanillaChestLoot.java.patch index 289351cfa27d..511748b2a25e 100644 --- a/paper-server/patches/sources/net/minecraft/data/loot/packs/VanillaChestLoot.java.patch +++ b/paper-server/patches/sources/net/minecraft/data/loot/packs/VanillaChestLoot.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/data/loot/packs/VanillaChestLoot.java +++ b/net/minecraft/data/loot/packs/VanillaChestLoot.java -@@ -1046,7 +_,6 @@ +@@ -1047,7 +_,6 @@ .add( LootItem.lootTableItem(Items.COMPASS) .apply(SetItemCountFunction.setCount(ConstantValue.exactly(1.0F))) diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestInfo.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestInfo.java.patch index b41f4ca1b28a..c8961dd01ea1 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestInfo.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestInfo.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/gametest/framework/GameTestInfo.java +++ b/net/minecraft/gametest/framework/GameTestInfo.java -@@ -244,7 +_,7 @@ - AABB structureBounds = this.getStructureBounds(); - List entitiesOfClass = this.getLevel() - .getEntitiesOfClass(Entity.class, structureBounds.inflate(1.0), entity -> !(entity instanceof Player)); -- entitiesOfClass.forEach(entity -> entity.remove(Entity.RemovalReason.DISCARDED)); -+ entitiesOfClass.forEach(entity -> entity.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper +@@ -246,7 +_,7 @@ + this.finish(); + AABB bounds = this.getStructureBounds(); + List entities = this.getLevel().getEntitiesOfClass(Entity.class, bounds.inflate(1.0), mob -> !(mob instanceof Player)); +- entities.forEach(e -> e.remove(Entity.RemovalReason.DISCARDED)); ++ entities.forEach(e -> e.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper } } diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestMainUtil.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestMainUtil.java.patch index c7d9012b3e1e..6ffa6037b761 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestMainUtil.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestMainUtil.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/gametest/framework/GameTestMainUtil.java +++ b/net/minecraft/gametest/framework/GameTestMainUtil.java -@@ -75,7 +_,7 @@ - copyPacks(string, string1); +@@ -83,7 +_,7 @@ + copyPacks(universePath, packFolder); } -- LevelStorageSource.LevelStorageAccess levelStorageAccess = LevelStorageSource.createDefault(Paths.get(string)).createAccess("gametestworld"); -+ LevelStorageSource.LevelStorageAccess levelStorageAccess = LevelStorageSource.createDefault(Paths.get(string)).createAccess("gametestworld", net.minecraft.world.level.dimension.LevelStem.OVERWORLD); // Paper - PackRepository packRepository = ServerPacksSource.createPackRepository(levelStorageAccess); +- LevelStorageSource.LevelStorageAccess levelStorageSource = LevelStorageSource.createDefault(Paths.get(universePath)).createAccess("gametestworld"); ++ LevelStorageSource.LevelStorageAccess levelStorageSource = LevelStorageSource.createDefault(Paths.get(universePath)).createAccess("gametestworld", net.minecraft.world.level.dimension.LevelStem.OVERWORLD); // Paper + PackRepository packRepository = ServerPacksSource.createPackRepository(levelStorageSource); MinecraftServer.spin( - thread -> GameTestServer.create(thread, levelStorageAccess, packRepository, optionalFromOption(optionSet, tests), optionSet.has(verify)) + thread -> GameTestServer.create( diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch index 1ab2a5ca3a50..3cd39b15ac0a 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch @@ -1,35 +1,38 @@ --- a/net/minecraft/gametest/framework/GameTestServer.java +++ b/net/minecraft/gametest/framework/GameTestServer.java -@@ -146,6 +_,8 @@ - boolean verify +@@ -155,6 +_,8 @@ + final int repeatCount ) { super( + null, // Paper + null, // Paper serverThread, - storageSource, + levelStorageSource, packRepository, -@@ -161,9 +_,17 @@ +@@ -173,13 +_,21 @@ @Override - public boolean initServer() { -- this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) {}); + protected boolean initServer() { + // Paper start -+ this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) { + this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) { + { + Objects.requireNonNull(GameTestServer.this); + } ++ + @Override + public void loadAndSaveFiles() { + throw new UnsupportedOperationException("Should not be called in a GameTestServer"); + } -+ }); + }); + this.initPostWorld(); Gizmos.withCollector(GizmoCollector.NOOP); - this.loadLevel(); + this.loadLevel("blah"); + // Paper end - ServerLevel serverLevel = this.overworld(); - this.testBatches = this.evaluateTestsToRun(serverLevel); + ServerLevel level = this.overworld(); + this.testBatches = this.evaluateTestsToRun(level); LOGGER.info("Started game test server"); -@@ -348,6 +_,13 @@ +@@ -385,6 +_,13 @@ return false; } @@ -41,9 +44,9 @@ + // Paper end + @Override - public boolean isSingleplayerOwner(NameAndId nameAndId) { + public boolean isSingleplayerOwner(final NameAndId nameAndId) { return false; -@@ -395,5 +_,16 @@ +@@ -432,5 +_,16 @@ @Override public void save() { } diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/StructureUtils.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/StructureUtils.java.patch index b367e2c5afda..60705bfeefa0 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/StructureUtils.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/StructureUtils.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/gametest/framework/StructureUtils.java +++ b/net/minecraft/gametest/framework/StructureUtils.java @@ -85,7 +_,7 @@ - level.clearBlockEvents(boundingBox); - AABB aabb = AABB.of(boundingBox); - List entitiesOfClass = level.getEntitiesOfClass(Entity.class, aabb, entity -> !(entity instanceof Player)); -- entitiesOfClass.forEach(Entity::discard); -+ entitiesOfClass.forEach(entity -> entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper + level.clearBlockEvents(structureBoundingBox); + AABB bounds = AABB.of(structureBoundingBox); + List livingEntities = level.getEntitiesOfClass(Entity.class, bounds, mob -> !(mob instanceof Player)); +- livingEntities.forEach(Entity::discard); ++ livingEntities.forEach(entity -> entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper } - public static BlockPos getTransformedFarCorner(BlockPos pos, Vec3i offset, Rotation rotation) { + public static BlockPos getTransformedFarCorner(final BlockPos structurePosition, final Vec3i size, final Rotation rotation) { diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/TestEnvironmentDefinition.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/TestEnvironmentDefinition.java.patch index f705c709f77c..54b94a7b7ced 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/TestEnvironmentDefinition.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/TestEnvironmentDefinition.java.patch @@ -1,20 +1,29 @@ --- a/net/minecraft/gametest/framework/TestEnvironmentDefinition.java +++ b/net/minecraft/gametest/framework/TestEnvironmentDefinition.java -@@ -124,7 +_,7 @@ - public void setup(ServerLevel level) { +@@ -184,7 +_,7 @@ + GameRuleMap originalState = GameRuleMap.of(); GameRules gameRules = level.getGameRules(); - MinecraftServer server = level.getServer(); -- gameRules.setAll(this.gameRulesMap, server); + this.gameRulesMap.keySet().forEach(rule -> setFromActive(originalState, (GameRule)rule, gameRules)); +- gameRules.setAll(this.gameRulesMap, level.getServer()); + gameRules.setAll(this.gameRulesMap, level); // Paper - per-world game rules + return originalState; } - @Override -@@ -133,7 +_,7 @@ - } +@@ -194,7 +_,7 @@ - private void resetRule(ServerLevel level, GameRule rule) { -- level.getGameRules().set(rule, rule.defaultValue(), level.getServer()); -+ level.getGameRules().set(rule, rule.defaultValue(), level); // Paper - per-world game rules + @Override + public void teardown(final ServerLevel level, final GameRuleMap saveData) { +- level.getGameRules().setAll(saveData, level.getServer()); ++ level.getGameRules().setAll(saveData, level); // Paper - per-world game rules } @Override +@@ -286,7 +_,7 @@ + } + + void apply(final ServerLevel level) { +- level.getServer().setWeatherParameters(this.clearTime, this.rainTime, this.raining, this.thundering); ++ level.getServer().setWeatherParameters(level, this.clearTime, this.rainTime, this.raining, this.thundering); // Paper - per-level WeatherData + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/nbt/ByteArrayTag.java.patch b/paper-server/patches/sources/net/minecraft/nbt/ByteArrayTag.java.patch index 2d195ba0b8fb..736b116f87bd 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/ByteArrayTag.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/ByteArrayTag.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/nbt/ByteArrayTag.java +++ b/net/minecraft/nbt/ByteArrayTag.java @@ -23,6 +_,7 @@ - private static byte[] readAccounted(DataInput input, NbtAccounter accounter) throws IOException { + private static byte[] readAccounted(final DataInput input, final NbtAccounter accounter) throws IOException { accounter.accountBytes(24L); - int _int = input.readInt(); -+ com.google.common.base.Preconditions.checkArgument(_int < 1 << 24); // Spigot - accounter.accountBytes(1L, _int); - byte[] bytes = new byte[_int]; - input.readFully(bytes); + int length = input.readInt(); ++ com.google.common.base.Preconditions.checkArgument(length < 1 << 24); // Spigot + accounter.accountBytes(1L, length); + byte[] data = new byte[length]; + input.readFully(data); diff --git a/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch b/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch index c07e64d19e6c..651d45dd8b23 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch @@ -2,13 +2,13 @@ +++ b/net/minecraft/nbt/CompoundTag.java @@ -54,7 +_,7 @@ - private static CompoundTag loadCompound(DataInput input, NbtAccounter nbtAccounter) throws IOException { - nbtAccounter.accountBytes(48L); -- Map map = Maps.newHashMap(); -+ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag + private static CompoundTag loadCompound(final DataInput input, final NbtAccounter accounter) throws IOException { + accounter.accountBytes(48L); +- Map values = Maps.newHashMap(); ++ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap values = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(8, 0.8f); // Paper - Reduce memory footprint of CompoundTag - byte b; - while ((b = input.readByte()) != 0) { + byte tagType; + while ((tagType = input.readByte()) != 0) { @@ -171,7 +_,7 @@ } @@ -22,9 +22,9 @@ @Override public CompoundTag copy() { -- HashMap map = new HashMap<>(); -- this.tags.forEach((key, value) -> map.put(key, value.copy())); -- return new CompoundTag(map); +- HashMap newTags = new HashMap<>(); +- this.tags.forEach((key, tag) -> newTags.put(key, tag.copy())); +- return new CompoundTag(newTags); + // Paper start - Reduce memory footprint of CompoundTag + it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap ret = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.tags.size(), 0.8f); + java.util.Iterator> iterator = (this.tags instanceof it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ? ((it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)this.tags).object2ObjectEntrySet().fastIterator() : this.tags.entrySet().iterator(); @@ -39,30 +39,30 @@ @Override @@ -523,22 +_,47 @@ - this.merge((CompoundTag)mapCodec.encoder().encodeStart(ops, data).getOrThrow()); + this.merge((CompoundTag)codec.encoder().encodeStart(ops, value).getOrThrow()); } -- public Optional read(String key, Codec codec) { -+ public Optional read(String key, Codec codec) { // Paper - option to read via codec without logging errors - diff on change - return this.read(key, codec, NbtOps.INSTANCE); +- public Optional read(final String name, final Codec codec) { ++ public Optional read(final String name, final Codec codec) { // Paper - option to read via codec without logging errors - diff on change + return this.read(name, codec, NbtOps.INSTANCE); } -- public Optional read(String key, Codec codec, DynamicOps ops) { -+ public Optional read(String key, Codec codec, DynamicOps ops) { // Paper - option to read via codec without logging errors - diff on change - Tag tag = this.get(key); +- public Optional read(final String name, final Codec codec, final DynamicOps ops) { ++ public Optional read(final String name, final Codec codec, final DynamicOps ops) { // Paper - option to read via codec without logging errors - diff on change + Tag tag = this.get(name); return tag == null ? Optional.empty() - : codec.parse(ops, tag).resultOrPartial(string -> LOGGER.error("Failed to read field ({}={}): {}", key, tag, string)); + : codec.parse(ops, tag).resultOrPartial(error -> LOGGER.error("Failed to read field ({}={}): {}", name, tag, error)); } -- public Optional read(MapCodec mapCodec) { -+ public Optional read(MapCodec mapCodec) { // Paper - option to read via codec without logging errors - diff on change - return this.read(mapCodec, NbtOps.INSTANCE); +- public Optional read(final MapCodec codec) { ++ public Optional read(final MapCodec codec) { // Paper - option to read via codec without logging errors - diff on change + return this.read(codec, NbtOps.INSTANCE); } -- public Optional read(MapCodec mapCodec, DynamicOps ops) { -+ public Optional read(MapCodec mapCodec, DynamicOps ops) { // Paper - option to read via codec without logging errors - diff on change - return mapCodec.decode(ops, ops.getMap(this).getOrThrow()).resultOrPartial(string -> LOGGER.error("Failed to read value ({}): {}", this, string)); +- public Optional read(final MapCodec codec, final DynamicOps ops) { ++ public Optional read(final MapCodec codec, final DynamicOps ops) { // Paper - option to read via codec without logging errors - diff on change + return codec.decode(ops, ops.getMap(this).getOrThrow()).resultOrPartial(error -> LOGGER.error("Failed to read value ({}): {}", this, error)); } + + // Paper start - option to read via codec without logging errors @@ -70,23 +70,23 @@ + // Copying was chosen over overloading the read methods as a boolean parameter to mark a method as quiet + // is not intuitive and would require even more overloads. + // Not a lot of diff in these methods is expected -+ public Optional readQuiet(String key, Codec codec) { -+ return this.readQuiet(key, codec, NbtOps.INSTANCE); ++ public Optional readQuiet(String name, Codec codec) { ++ return this.readQuiet(name, codec, NbtOps.INSTANCE); + } + -+ public Optional readQuiet(String key, Codec codec, DynamicOps ops) { -+ Tag tag = this.get(key); ++ public Optional readQuiet(String name, Codec codec, DynamicOps ops) { ++ Tag tag = this.get(name); + return tag == null + ? Optional.empty() + : codec.parse(ops, tag).resultOrPartial(); + } + -+ public Optional readQuiet(MapCodec mapCodec) { -+ return this.readQuiet(mapCodec, NbtOps.INSTANCE); ++ public Optional readQuiet(MapCodec codec) { ++ return this.readQuiet(codec, NbtOps.INSTANCE); + } + -+ public Optional readQuiet(MapCodec mapCodec, DynamicOps ops) { -+ return mapCodec.decode(ops, ops.getMap(this).getOrThrow()).resultOrPartial(); ++ public Optional readQuiet(MapCodec codec, DynamicOps ops) { ++ return codec.decode(ops, ops.getMap(this).getOrThrow()).resultOrPartial(); + } + // Paper end - option to read via codec without logging errors } diff --git a/paper-server/patches/sources/net/minecraft/nbt/IntArrayTag.java.patch b/paper-server/patches/sources/net/minecraft/nbt/IntArrayTag.java.patch index de1fb28f75f5..cb478c6240fd 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/IntArrayTag.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/IntArrayTag.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/nbt/IntArrayTag.java +++ b/net/minecraft/nbt/IntArrayTag.java @@ -23,6 +_,7 @@ - private static int[] readAccounted(DataInput input, NbtAccounter accounter) throws IOException { + private static int[] readAccounted(final DataInput input, final NbtAccounter accounter) throws IOException { accounter.accountBytes(24L); - int _int = input.readInt(); -+ com.google.common.base.Preconditions.checkArgument(_int < 1 << 24); // Spigot - accounter.accountBytes(4L, _int); - int[] ints = new int[_int]; + int length = input.readInt(); ++ com.google.common.base.Preconditions.checkArgument(length < 1 << 24); // Spigot + accounter.accountBytes(4L, length); + int[] data = new int[length]; diff --git a/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch b/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch index 5cd314e969fc..e94e7511736f 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch @@ -1,14 +1,16 @@ --- a/net/minecraft/nbt/NbtIo.java +++ b/net/minecraft/nbt/NbtIo.java -@@ -118,6 +_,11 @@ +@@ -117,7 +_,12 @@ + return read(input, NbtAccounter.unlimitedHeap()); } - public static CompoundTag read(DataInput input, NbtAccounter accounter) throws IOException { -+ // Spigot start +- public static CompoundTag read(final DataInput input, final NbtAccounter accounter) throws IOException { ++ // Spigot start ++ public static CompoundTag read(DataInput input, final NbtAccounter accounter) throws IOException { + if (input instanceof io.netty.buffer.ByteBufInputStream byteBufInputStream) { + input = new DataInputStream(new org.spigotmc.LimitStream(byteBufInputStream, accounter)); + } + // Spigot end - Tag unnamedTag = readUnnamedTag(input, accounter); - if (unnamedTag instanceof CompoundTag) { - return (CompoundTag)unnamedTag; + Tag tag = readUnnamedTag(input, accounter); + if (tag instanceof CompoundTag) { + return (CompoundTag)tag; diff --git a/paper-server/patches/sources/net/minecraft/nbt/SnbtGrammar.java.patch b/paper-server/patches/sources/net/minecraft/nbt/SnbtGrammar.java.patch index f32f5b684f24..83043f4aafb1 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/SnbtGrammar.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/SnbtGrammar.java.patch @@ -1,21 +1,23 @@ --- a/net/minecraft/nbt/SnbtGrammar.java +++ b/net/minecraft/nbt/SnbtGrammar.java -@@ -587,7 +_,7 @@ - Atom>> atom30 = Atom.of("map_entries"); - dictionary.put(atom30, Term.repeatedWithTrailingSeparator(namedRule3, atom30, StringReaderTerms.character(',')), scope -> scope.getOrThrow(atom30)); - Atom atom31 = Atom.of("map_literal"); -- dictionary.put(atom31, Term.sequence(StringReaderTerms.character('{'), dictionary.named(atom30), StringReaderTerms.character('}')), scope -> { -+ dictionary.put(atom31, Term.sequence(StringReaderTerms.character('{'), Scope.increaseDepth(), dictionary.named(atom30), Scope.decreaseDepth(), StringReaderTerms.character('}')), scope -> { // Paper - track depth - List> list = scope.getOrThrow(atom30); - if (list.isEmpty()) { - return object2; -@@ -622,7 +_,9 @@ - atom35, +@@ -619,7 +_,7 @@ + mapEntries, Term.repeatedWithTrailingSeparator(mapEntryRule, mapEntries, StringReaderTerms.character(',')), scope -> scope.getOrThrow(mapEntries) + ); + Atom mapLiteral = Atom.of("map_literal"); +- rules.put(mapLiteral, Term.sequence(StringReaderTerms.character('{'), rules.named(mapEntries), StringReaderTerms.character('}')), scope -> { ++ rules.put(mapLiteral, Term.sequence(StringReaderTerms.character('{'), Scope.increaseDepth(), rules.named(mapEntries), Scope.decreaseDepth(), StringReaderTerms.character('}')), scope -> { // Paper - track depth + List> entries = scope.getOrThrow(mapEntries); + if (entries.isEmpty()) { + return emptyMapValue; +@@ -660,9 +_,11 @@ + listLiteral, Term.sequence( StringReaderTerms.character('['), + Scope.increaseDepth(), // Paper - track depth - Term.alternative(Term.sequence(dictionary.named(atom33), StringReaderTerms.character(';'), dictionary.named(atom34)), dictionary.named(atom32)), + Term.alternative( + Term.sequence(rules.named(arrayPrefix), StringReaderTerms.character(';'), rules.named(intArrayEntries)), rules.named(listEntries) + ), + Scope.decreaseDepth(), // Paper - track depth StringReaderTerms.character(']') ), - parseState -> { + state -> { diff --git a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch index 9e277b37beeb..9f02aa6675d9 100644 --- a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch @@ -15,12 +15,12 @@ @@ -81,6 +_,43 @@ private boolean handlingFault; private volatile @Nullable DisconnectionDetails delayedDisconnect; - @Nullable BandwidthDebugMonitor bandwidthDebugMonitor; + private @Nullable BandwidthDebugMonitor bandwidthDebugMonitor; + public String hostname = ""; // CraftBukkit - add field + // Paper start - NetworkClient implementation + public int protocolVersion; + public java.net.InetSocketAddress virtualHost; -+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing ++ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit connection flushing + // Paper end + // Paper start - add utility methods + public final net.minecraft.server.level.ServerPlayer getPlayer() { @@ -54,7 +54,7 @@ + public net.minecraft.server.level.@Nullable ServerPlayer savedPlayerForLegacyEvents; // Paper - playerloginevent & PlayerSpawnLocationEvent + public org.bukkit.event.player.PlayerResourcePackStatusEvent.@Nullable Status resourcePackStatus; // Paper - public Connection(PacketFlow receiving) { + public Connection(final PacketFlow receiving) { this.receiving = receiving; @@ -91,6 +_,7 @@ super.channelActive(ctx); @@ -64,56 +64,58 @@ if (this.delayedDisconnect != null) { this.disconnect(this.delayedDisconnect); } -@@ -103,14 +_,31 @@ +@@ -102,15 +_,32 @@ + } @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable exception) { -+ // Paper start - Handle large packets disconnecting client -+ if (exception instanceof io.netty.handler.codec.EncoderException && exception.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { +- public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) { ++ // Paper start - Handle large packets disconnecting client ++ public void exceptionCaught(final ChannelHandlerContext ctx, Throwable cause) { ++ if (cause instanceof io.netty.handler.codec.EncoderException && cause.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { + final Packet packet = packetTooLargeException.getPacket(); + if (packet.packetTooLarge(this)) { + ProtocolSwapHandler.handleOutboundTerminalPacket(ctx, packet); + return; + } else if (packet.isSkippable()) { -+ Connection.LOGGER.debug("Skipping packet due to errors", exception.getCause()); ++ Connection.LOGGER.debug("Skipping packet due to errors", cause.getCause()); + ProtocolSwapHandler.handleOutboundTerminalPacket(ctx, packet); + return; + } else { -+ exception = exception.getCause(); ++ cause = cause.getCause(); + } + } + // Paper end - Handle large packets disconnecting client - if (exception instanceof SkipPacketException) { - LOGGER.debug("Skipping packet due to errors", exception.getCause()); + if (cause instanceof SkipPacketException) { + LOGGER.debug("Skipping packet due to errors", cause.getCause()); } else { - boolean flag = !this.handlingFault; + boolean isFirstFault = !this.handlingFault; this.handlingFault = true; if (this.channel.isOpen()) { + net.minecraft.server.level.ServerPlayer player = this.getPlayer(); // Paper - Add API for quit reason - if (exception instanceof TimeoutException) { - LOGGER.debug("Timeout", exception); + if (cause instanceof TimeoutException) { + LOGGER.debug("Timeout", cause); + if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.TIMED_OUT; // Paper - Add API for quit reason this.disconnect(Component.translatable("disconnect.timeout")); } else { - Component component = Component.translatable("disconnect.genericReason", "Internal Exception: " + exception); + Component reason = Component.translatable("disconnect.genericReason", "Internal Exception: " + cause); @@ -122,9 +_,11 @@ - disconnectionDetails = new DisconnectionDetails(component); + details = new DisconnectionDetails(reason); } + if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.ERRONEOUS_STATE; // Paper - Add API for quit reason - if (flag) { - LOGGER.debug("Failed to sent packet", exception); + if (isFirstFault) { + LOGGER.debug("Failed to sent packet", cause); - if (this.getSending() == PacketFlow.CLIENTBOUND) { + boolean doesDisconnectExist = this.packetListener.protocol() != ConnectionProtocol.STATUS && this.packetListener.protocol() != ConnectionProtocol.HANDSHAKING; // Paper + if (this.getSending() == PacketFlow.CLIENTBOUND && doesDisconnectExist) { // Paper Packet packet = (Packet)(this.sendLoginDisconnect - ? new ClientboundLoginDisconnectPacket(component) - : new ClientboundDisconnectPacket(component)); + ? new ClientboundLoginDisconnectPacket(reason) + : new ClientboundDisconnectPacket(reason)); @@ -141,6 +_,7 @@ } } } -+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Spigot // Paper ++ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(cause); // Spigot // Paper } @Override @@ -152,7 +154,7 @@ + case DROP: + return; + case KICK: -+ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName()); ++ String deobfedPacketName = check.getName(); + + String playerName; + if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { @@ -178,7 +180,7 @@ } catch (RejectedExecutionException var6) { this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); } catch (ClassCastException var7) { -@@ -346,10 +_,30 @@ +@@ -344,10 +_,30 @@ } } @@ -193,7 +195,7 @@ + Connection.joinAttemptsThisTick = 0; + } + // Paper end - Buffer joins to world - if (this.packetListener instanceof TickablePacketListener tickablePacketListener) { + if (this.packetListener instanceof TickablePacketListener tickable) { + // Paper start - Buffer joins to world + if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) + || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING @@ -201,7 +203,7 @@ + // Paper start - detailed watchdog information + net.minecraft.network.PacketProcessor.packetProcessing.push(this.packetListener); + try { - tickablePacketListener.tick(); + tickable.tick(); + } finally { + net.minecraft.network.PacketProcessor.packetProcessing.pop(); + } // Paper end - detailed watchdog information @@ -209,31 +211,31 @@ } if (!this.isConnected() && !this.disconnectionHandled) { -@@ -357,7 +_,7 @@ +@@ -355,7 +_,7 @@ } if (this.channel != null) { - this.channel.flush(); -+ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - Disable explicit network manager flushing; we don't need to explicit flush here, but allow opt in incase issues are found to a better version ++ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - Disable explicit connection flushing; we don't need to explicit flush here, but allow opt in incase issues are found to a better version } if (this.tickCount++ % 20 == 0) { -@@ -393,12 +_,13 @@ +@@ -391,12 +_,13 @@ } - public void disconnect(DisconnectionDetails disconnectionDetails) { + public void disconnect(final DisconnectionDetails details) { + this.preparing = false; // Spigot if (this.channel == null) { - this.delayedDisconnect = disconnectionDetails; + this.delayedDisconnect = details; } if (this.isConnected()) { - this.channel.close().awaitUninterruptibly(); + this.channel.close(); // We can't wait as this may be called from an event loop. - this.disconnectionDetails = disconnectionDetails; + this.disconnectionDetails = details; } } -@@ -533,6 +_,13 @@ +@@ -543,6 +_,13 @@ } } @@ -244,10 +246,10 @@ + } + } + // Paper end - add proper async disconnect - public void setupCompression(int threshold, boolean validateDecompressed) { + public void setupCompression(final int threshold, final boolean validateDecompressed) { if (threshold >= 0) { if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder compressionDecoder) { -@@ -546,6 +_,7 @@ +@@ -556,6 +_,7 @@ } else { this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(threshold)); } @@ -255,7 +257,7 @@ } else { if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { this.channel.pipeline().remove("decompress"); -@@ -554,6 +_,7 @@ +@@ -564,6 +_,7 @@ if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { this.channel.pipeline().remove("compress"); } @@ -263,9 +265,9 @@ } } -@@ -571,6 +_,26 @@ +@@ -581,6 +_,26 @@ ); - packetListener1.onDisconnect(disconnectionDetails); + disconnectListener.onDisconnect(details); } + this.pendingActions.clear(); // Free up packet queue. + // Paper start - Add PlayerConnectionCloseEvent diff --git a/paper-server/patches/sources/net/minecraft/network/DisconnectionDetails.java.patch b/paper-server/patches/sources/net/minecraft/network/DisconnectionDetails.java.patch index 434d042dcdfd..468ba760fe0b 100644 --- a/paper-server/patches/sources/net/minecraft/network/DisconnectionDetails.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/DisconnectionDetails.java.patch @@ -12,6 +12,6 @@ + } +// Paper end - Configuration API: add support for enhanced disconnection causes + - public DisconnectionDetails(Component reason) { + public DisconnectionDetails(final Component reason) { this(reason, Optional.empty(), Optional.empty()); } diff --git a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch index c4e2ef021142..d477f5aab15b 100644 --- a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch @@ -16,7 +16,7 @@ + public byte codecDepth; + // Paper end - Track codec depth - public FriendlyByteBuf(ByteBuf source) { + public FriendlyByteBuf(final ByteBuf source) { + this.adventure$locale = PacketEncoder.ADVENTURE_LOCALE.get(); // Paper - track player's locale for server-side translations this.source = source; } @@ -24,22 +24,22 @@ @@ -106,8 +_,13 @@ } - public void writeJsonWithCodec(Codec codec, T value) { + public void writeJsonWithCodec(final Codec codec, final T value) { + // Paper start - Adventure; add max length parameter + this.writeJsonWithCodec(codec, value, MAX_STRING_LENGTH); + } + public void writeJsonWithCodec(Codec codec, T value, int maxLength) { + // Paper end - Adventure; add max length parameter - DataResult dataResult = codec.encodeStart(JsonOps.INSTANCE, value); -- this.writeUtf(GSON.toJson(dataResult.getOrThrow(exception -> new EncoderException("Failed to encode: " + exception + " " + value)))); -+ this.writeUtf(GSON.toJson(dataResult.getOrThrow(exception -> new EncoderException("Failed to encode: " + exception + " " + value))), maxLength); // Paper - Adventure; add max length parameter + DataResult result = codec.encodeStart(JsonOps.INSTANCE, value); +- this.writeUtf(GSON.toJson(result.getOrThrow(error -> new EncoderException("Failed to encode: " + error + " " + value)))); ++ this.writeUtf(GSON.toJson(result.getOrThrow(error -> new EncoderException("Failed to encode: " + error + " " + value))), maxLength); // Paper - Adventure; add max length parameter } - public static IntFunction limitValue(IntFunction function, int limit) { -@@ -552,7 +_,7 @@ + public static IntFunction limitValue(final IntFunction original, final int limit) { +@@ -530,7 +_,7 @@ try { - NbtIo.writeAnyTag(tag, new ByteBufOutputStream(buffer)); + NbtIo.writeAnyTag(tag, new ByteBufOutputStream(output)); - } catch (IOException var3) { + } catch (Exception var3) { // CraftBukkit - IOException -> Exception throw new EncoderException(var3); diff --git a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch index 7318c99f0cd6..ad66db91b916 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch @@ -6,25 +6,25 @@ + static final ThreadLocal ADVENTURE_LOCALE = ThreadLocal.withInitial(() -> null); // Paper - adventure; set player's locale @Override - protected void encode(ChannelHandlerContext channelHandlerContext, Packet packet, ByteBuf byteBuf) throws Exception { - PacketType> packetType = packet.type(); + protected void encode(final ChannelHandlerContext ctx, final Packet packet, final ByteBuf output) throws Exception { + PacketType> packetId = packet.type(); try { -+ ADVENTURE_LOCALE.set(channelHandlerContext.channel().attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).get()); // Paper - adventure; set player's locale - this.protocolInfo.codec().encode(byteBuf, packet); - int i = byteBuf.readableBytes(); ++ ADVENTURE_LOCALE.set(ctx.channel().attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).get()); // Paper - adventure; set player's locale + this.protocolInfo.codec().encode(output, packet); + int writtenBytes = output.readableBytes(); if (LOGGER.isDebugEnabled()) { -@@ -39,7 +_,33 @@ +@@ -44,7 +_,33 @@ throw var9; } finally { + // Paper start - Handle large packets disconnecting client -+ int packetLength = byteBuf.readableBytes(); ++ int packetLength = output.readableBytes(); + if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) { + throw new PacketTooLargeException(packet, packetLength); + } + // Paper end - Handle large packets disconnecting client - ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet); + ProtocolSwapHandler.handleOutboundTerminalPacket(ctx, packet); } } + diff --git a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch index 79eaf236b146..9d468f157102 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch @@ -24,7 +24,7 @@ return Thread.currentThread() == this.runningThread; } - public void scheduleIfPossible(T listener, Packet packet) { + public void scheduleIfPossible(final T listener, final Packet packet) { if (this.closed) { - throw new RejectedExecutionException("Server already shutting down"); + throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop @@ -67,7 +67,7 @@ + } + // Paper end - detailed watchdog information + - record ListenerAndPacket(T listener, Packet packet) { + private record ListenerAndPacket(T listener, Packet packet) { public void handle() { + packetProcessing.push(this.listener); // Paper - detailed watchdog information + try { // Paper - detailed watchdog information diff --git a/paper-server/patches/sources/net/minecraft/network/VarInt.java.patch b/paper-server/patches/sources/net/minecraft/network/VarInt.java.patch index 8604de1e1d78..f8ba553dc627 100644 --- a/paper-server/patches/sources/net/minecraft/network/VarInt.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/VarInt.java.patch @@ -3,9 +3,9 @@ @@ -9,6 +_,18 @@ private static final int DATA_BITS_PER_BYTE = 7; - public static int getByteSize(int data) { + public static int getByteSize(final int value) { + // Paper start - Optimize VarInts -+ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(data)]; ++ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(value)]; + } + private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33]; + static { @@ -14,30 +14,30 @@ + } + VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0. + } -+ public static int getByteSizeOld(int data) { ++ public static int getByteSizeOld(final int value) { + // Paper end - Optimize VarInts for (int i = 1; i < MAX_VARINT_SIZE; i++) { - if ((data & -1 << i * 7) == 0) { + if ((value & -1 << i * 7) == 0) { return i; @@ -39,6 +_,21 @@ } - public static ByteBuf write(ByteBuf buffer, int value) { + public static ByteBuf write(final ByteBuf output, int value) { + // Paper start - Optimize VarInts + // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes + // that the proxy will write, to improve inlining. + if ((value & (0xFFFFFFFF << 7)) == 0) { -+ buffer.writeByte(value); ++ output.writeByte(value); + } else if ((value & (0xFFFFFFFF << 14)) == 0) { + int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); -+ buffer.writeShort(w); ++ output.writeShort(w); + } else { -+ writeOld(buffer, value); ++ writeOld(output, value); + } -+ return buffer; ++ return output; + } -+ public static ByteBuf writeOld(ByteBuf buffer, int value) { ++ public static ByteBuf writeOld(final ByteBuf output, int value) { + // Paper end - Optimize VarInts while ((value & -128) != 0) { - buffer.writeByte(value & 127 | 128); + output.writeByte(value & 127 | 128); value >>>= 7; diff --git a/paper-server/patches/sources/net/minecraft/network/Varint21FrameDecoder.java.patch b/paper-server/patches/sources/net/minecraft/network/Varint21FrameDecoder.java.patch index 46628723821a..e948af5ebd9c 100644 --- a/paper-server/patches/sources/net/minecraft/network/Varint21FrameDecoder.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Varint21FrameDecoder.java.patch @@ -3,7 +3,7 @@ @@ -40,6 +_,12 @@ @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { + protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List out) { + // Paper start - Perf: Optimize exception handling; if channel is not active just discard the packet + if (!ctx.channel().isActive()) { + in.skipBytes(in.readableBytes()); diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch index b340bb0c3041..92c2aeb9a395 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch @@ -4,16 +4,16 @@ @FunctionalInterface public interface ChatDecorator { -- ChatDecorator PLAIN = (player, message) -> message; +- ChatDecorator PLAIN = (player, plain) -> plain; - -- Component decorate(@Nullable ServerPlayer player, Component message); -+ ChatDecorator PLAIN = (player, message) -> java.util.concurrent.CompletableFuture.completedFuture(message); // Paper - adventure; support async chat decoration events +- Component decorate(@Nullable ServerPlayer player, Component plain); ++ ChatDecorator PLAIN = (player, plain) -> java.util.concurrent.CompletableFuture.completedFuture(plain); // Paper - adventure; support async chat decoration events + + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - adventure; support chat decoration events (callers should use the overload with CommandSourceStack) -+ java.util.concurrent.CompletableFuture decorate(@Nullable ServerPlayer player, Component message); // Paper - adventure; support async chat decoration events ++ java.util.concurrent.CompletableFuture decorate(@Nullable ServerPlayer player, Component plain); // Paper - adventure; support async chat decoration events + + // Paper start - adventure; support async chat decoration events -+ default java.util.concurrent.CompletableFuture decorate(@Nullable ServerPlayer sender, net.minecraft.commands.@Nullable CommandSourceStack commandSourceStack, Component message) { ++ default java.util.concurrent.CompletableFuture decorate(@Nullable ServerPlayer sender, net.minecraft.commands.@Nullable CommandSourceStack commandSourceStack, Component plain) { + throw new UnsupportedOperationException("Must override this implementation"); + } + // Paper end - adventure; support async chat decoration events diff --git a/paper-server/patches/sources/net/minecraft/network/chat/Component.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/Component.java.patch index 6159dbd6c797..6d624f287eec 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/Component.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/Component.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/chat/Component.java +++ b/net/minecraft/network/chat/Component.java -@@ -25,7 +_,19 @@ +@@ -27,7 +_,19 @@ import net.minecraft.world.level.ChunkPos; import org.jspecify.annotations.Nullable; diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch index 815a89c7d6b4..6e42e1ffbd8f 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch @@ -34,8 +34,8 @@ public static final StreamCodec> TRUSTED_OPTIONAL_STREAM_CODEC = TRUSTED_STREAM_CODEC.apply( ByteBufCodecs::optional ); -@@ -91,7 +_,25 @@ - return ExtraCodecs.orCompressed(mapCodec2, mapCodec1); +@@ -93,7 +_,25 @@ + return ExtraCodecs.orCompressed(contentsCodec, discriminatorCodec); } + // Paper start - adventure; create separate codec for each locale @@ -50,23 +50,23 @@ + } + // Paper end - adventure; create separate codec for each locale + - private static Codec createCodec(Codec codec) { + private static Codec createCodec(final Codec topSerializer) { + // Paper start - adventure; create separate codec for each locale -+ return createCodec(codec, null); ++ return createCodec(topSerializer, null); + } + -+ private static Codec createCodec(Codec codec, @javax.annotation.Nullable java.util.Locale locale) { ++ private static Codec createCodec(Codec topSerializer, java.util.@org.jspecify.annotations.Nullable Locale locale) { + // Paper end - adventure; create separate codec for each locale - ExtraCodecs.LateBoundIdMapper> lateBoundIdMapper = new ExtraCodecs.LateBoundIdMapper<>(); - bootstrap(lateBoundIdMapper); - MapCodec mapCodec = createLegacyComponentMatcher(lateBoundIdMapper, ComponentContents::codec, "type"); -@@ -103,6 +_,34 @@ + ExtraCodecs.LateBoundIdMapper> contentTypes = new ExtraCodecs.LateBoundIdMapper<>(); + bootstrap(contentTypes); + MapCodec compressedContentsCodec = createLegacyComponentMatcher(contentTypes, ComponentContents::codec, "type"); +@@ -105,6 +_,34 @@ ) - .apply(instance, MutableComponent::new) + .apply(i, MutableComponent::new) ); + // Paper start - adventure; create separate codec for each locale -+ final Codec origCodec = codec1; -+ codec1 = new Codec<>() { ++ final Codec origCodec = fullCodec; ++ fullCodec = new Codec<>() { + @Override + public DataResult> decode(final DynamicOps ops, final T input) { + return origCodec.decode(ops, input); @@ -92,6 +92,6 @@ + } + }; + // Paper end - adventure; create separate codec for each locale - return Codec.either(Codec.either(Codec.STRING, ExtraCodecs.nonEmptyList(codec.listOf())), codec1) + return Codec.either(Codec.either(Codec.STRING, ExtraCodecs.nonEmptyList(topSerializer.listOf())), fullCodec) .xmap( - either -> either.map(either1 -> either1.map(Component::literal, ComponentSerialization::createFromList), component -> (Component)component), + specialOrComponent -> specialOrComponent.map( diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch index 525b0643e6f4..22053517b89e 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch @@ -1,20 +1,22 @@ --- a/net/minecraft/network/chat/ComponentUtils.java +++ b/net/minecraft/network/chat/ComponentUtils.java -@@ -49,16 +_,45 @@ +@@ -47,6 +_,7 @@ } } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - validate separators - right now this method is only used for separator evaluation. Error on build if this changes to re-evaluate. - public static Optional updateForEntity( - @Nullable CommandSourceStack source, Optional optionalComponent, @Nullable Entity entity, int recursionDepth - ) throws CommandSyntaxException { - return optionalComponent.isPresent() ? Optional.of(updateForEntity(source, optionalComponent.get(), entity, recursionDepth)) : Optional.empty(); + public static Optional resolve(final ResolutionContext context, final Optional component, final int recursionDepth) throws CommandSyntaxException { + return component.isPresent() ? Optional.of(resolve(context, component.get(), recursionDepth)) : Optional.empty(); + } +@@ -55,13 +_,40 @@ + return resolve(context, component, 0); } +- public static MutableComponent resolve(final ResolutionContext context, final Component component, final int recursionDepth) throws CommandSyntaxException { + // Paper start - validate separator -+ public static Optional updateSeparatorForEntity(@Nullable CommandSourceStack source, Optional text, @Nullable Entity sender, int depth) throws CommandSyntaxException { ++ public static Optional resolveSeparator(final ResolutionContext context, final Optional text, final int recursionDepth) throws CommandSyntaxException { + if (text.isEmpty() || !isValidSelector(text.get())) return Optional.empty(); -+ return Optional.of(updateForEntity(source, text.get(), sender, depth)); ++ return Optional.of(resolve(context, text.get(), recursionDepth)); + } + + public static boolean isValidSelector(final Component component) { @@ -33,16 +35,18 @@ + } + // Paper end - validate separator + - public static MutableComponent updateForEntity(@Nullable CommandSourceStack source, Component component, @Nullable Entity entity, int recursionDepth) throws CommandSyntaxException { - if (recursionDepth > 100) { - return component.copy(); ++ public static MutableComponent resolve(final ResolutionContext context, Component component, final int recursionDepth) throws CommandSyntaxException { // Paper - adventure; pass actual vanilla component + if (recursionDepth > context.depthLimit()) { + return switch (context.depthLimitBehavior()) { + case DISCARD_REMAINING -> CommonComponents.ELLIPSIS.copy(); + case STOP_PROCESSING_AND_COPY_REMAINING -> component.copy(); + }; } else { + // Paper start - adventure; pass actual vanilla component + if (component instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { + component = adventureComponent.deepConverted(); + } + // Paper end - adventure; pass actual vanilla component -+ - MutableComponent mutableComponent = component.getContents().resolve(source, entity, recursionDepth + 1); + MutableComponent result = component.getContents().resolve(context, recursionDepth + 1); - for (Component component1 : component.getSiblings()) { + for (Component sibling : component.getSiblings()) { diff --git a/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch index 677316ab3cbe..71e7db277d02 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch @@ -3,12 +3,12 @@ @@ -97,6 +_,11 @@ @Override - public boolean equals(Object other) { + public boolean equals(final Object o) { + // Paper start - make AdventureComponent equivalent -+ if (other instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { -+ other = adventureComponent.deepConverted(); ++ if (o instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { ++ return this.equals(adventureComponent.deepConverted()); + } + // Paper end - make AdventureComponent equivalent - return this == other - || other instanceof MutableComponent mutableComponent - && this.contents.equals(mutableComponent.contents) + return this == o + || o instanceof MutableComponent that + && this.contents.equals(that.contents) diff --git a/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch index 929fe273908a..1c01a7e3c5f9 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch @@ -2,28 +2,28 @@ +++ b/net/minecraft/network/chat/OutgoingChatMessage.java @@ -7,6 +_,12 @@ - void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType); + void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound chatType); + // Paper start -+ default void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType, @javax.annotation.Nullable Component unsigned) { -+ this.sendToPlayer(player, filtered, boundChatType); ++ default void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType, final @org.jspecify.annotations.Nullable Component unsigned) { ++ this.sendToPlayer(player, filtered, chatType); + } + // Paper end + - static OutgoingChatMessage create(PlayerChatMessage message) { + static OutgoingChatMessage create(final PlayerChatMessage message) { return (OutgoingChatMessage)(message.isSystem() ? new OutgoingChatMessage.Disguised(message.decoratedContent()) @@ -16,7 +_,13 @@ public record Disguised(@Override Component content) implements OutgoingChatMessage { @Override - public void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType) { -- player.connection.sendDisguisedChatMessage(this.content, boundChatType); + public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType) { +- player.connection.sendDisguisedChatMessage(this.content, chatType); + // Paper start -+ this.sendToPlayer(player, filtered, boundChatType, null); ++ this.sendToPlayer(player, filtered, chatType, null); + } + @Override -+ public void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType, @javax.annotation.Nullable Component unsigned) { -+ player.connection.sendDisguisedChatMessage(unsigned != null ? unsigned : this.content, boundChatType); ++ public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType, final @org.jspecify.annotations.Nullable Component unsigned) { ++ player.connection.sendDisguisedChatMessage(unsigned != null ? unsigned : this.content, chatType); + // Paper end } } @@ -31,15 +31,15 @@ @@ -28,7 +_,14 @@ @Override - public void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType) { + public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType) { + // Paper start -+ this.sendToPlayer(player, filtered, boundChatType, null); ++ this.sendToPlayer(player, filtered, chatType, null); + } + @Override -+ public void sendToPlayer(ServerPlayer player, boolean filtered, ChatType.Bound boundChatType, @javax.annotation.Nullable Component unsigned) { ++ public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType, final @org.jspecify.annotations.Nullable Component unsigned) { + // Paper end - PlayerChatMessage playerChatMessage = this.message.filter(filtered); -+ playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper - if (!playerChatMessage.isFullyFiltered()) { - player.connection.sendPlayerChatMessage(playerChatMessage, boundChatType); + PlayerChatMessage filteredMessage = this.message.filter(filtered); ++ filteredMessage = unsigned != null ? filteredMessage.withUnsignedContent(unsigned) : filteredMessage; // Paper + if (!filteredMessage.isFullyFiltered()) { + player.connection.sendPlayerChatMessage(filteredMessage, chatType); } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch index f6d43730715a..55f2dc457ec1 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch @@ -42,21 +42,21 @@ + // Paper end - adventure; support signed messages + public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( + i -> i.group( SignedMessageLink.CODEC.fieldOf("link").forGetter(PlayerChatMessage::link), -@@ -48,7 +_,14 @@ +@@ -50,7 +_,14 @@ } - public PlayerChatMessage withUnsignedContent(Component message) { -- Component component = !message.equals(Component.literal(this.signedContent())) ? message : null; + public PlayerChatMessage withUnsignedContent(final Component content) { +- Component unsignedContent = !content.equals(Component.literal(this.signedContent())) ? content : null; + // Paper start - adventure -+ final Component component; -+ if (message instanceof io.papermc.paper.adventure.AdventureComponent advComponent) { -+ component = this.signedContent().equals(io.papermc.paper.adventure.AdventureCodecs.tryCollapseToString(advComponent.adventure$component())) ? null : message; ++ final Component unsignedContent; ++ if (content instanceof io.papermc.paper.adventure.AdventureComponent advComponent) { ++ unsignedContent = this.signedContent().equals(io.papermc.paper.adventure.AdventureCodecs.tryCollapseToString(advComponent.adventure$component())) ? null : content; + } else { -+ component = !message.equals(Component.literal(this.signedContent())) ? message : null; ++ unsignedContent = !content.equals(Component.literal(this.signedContent())) ? content : null; + } + // Paper end - adventure - return new PlayerChatMessage(this.link, this.signature, this.signedBody, component, this.filterMask); + return new PlayerChatMessage(this.link, this.signature, this.signedBody, unsignedContent, this.filterMask); } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch index 72366c94cd99..bd43bcbeab6e 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/network/chat/SignedMessageChain.java +++ b/net/minecraft/network/chat/SignedMessageChain.java -@@ -39,14 +_,14 @@ +@@ -44,14 +_,14 @@ if (signature == null) { throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.MISSING_PROFILE_KEY); - } else if (publicKey.data().hasExpired()) { + } else if (profilePublicKey.data().hasExpired()) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY); -+ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes ++ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes } else { - SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink; - if (signedMessageLink == null) { + SignedMessageLink link = SignedMessageChain.this.nextLink; + if (link == null) { throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN); } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { this.setChainBroken(); @@ -16,12 +16,12 @@ + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes } else { SignedMessageChain.this.lastTimeStamp = body.timeStamp(); - PlayerChatMessage playerChatMessage = new PlayerChatMessage(signedMessageLink, signature, body, null, FilterMask.PASS_THROUGH); -@@ -79,8 +_,15 @@ - static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature"); - static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat"); + PlayerChatMessage unpacked = new PlayerChatMessage(link, signature, body, null, FilterMask.PASS_THROUGH); +@@ -84,8 +_,15 @@ + private static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature"); + private static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat"); -- public DecodeException(Component component) { +- public DecodeException(final Component component) { + // Paper start + public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; + public DecodeException(Component component, org.bukkit.event.player.PlayerKickEvent.Cause event) { @@ -29,7 +29,7 @@ + this.kickCause = event; + } + // Paper end -+ public DecodeException(Component component) { ++ public DecodeException(final Component component) { + this(component, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); // Paper } } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/TextColor.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/TextColor.java.patch index 40288d32b2e2..aa4e4213f486 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/TextColor.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/TextColor.java.patch @@ -4,25 +4,25 @@ public static final Codec CODEC = Codec.STRING.comapFlatMap(TextColor::parseColor, TextColor::serialize); private static final Map LEGACY_FORMAT_TO_COLOR = Stream.of(ChatFormatting.values()) .filter(ChatFormatting::isColor) -- .collect(ImmutableMap.toImmutableMap(Function.identity(), formatting -> new TextColor(formatting.getColor(), formatting.getName()))); -+ .collect(ImmutableMap.toImmutableMap(Function.identity(), formatting -> new TextColor(formatting.getColor(), formatting.getName(), formatting))); // CraftBukkit +- .collect(ImmutableMap.toImmutableMap(Function.identity(), f -> new TextColor(f.getColor(), f.getName()))); ++ .collect(ImmutableMap.toImmutableMap(Function.identity(), f -> new TextColor(f.getColor(), f.getName(), f))); // CraftBukkit private static final Map NAMED_COLORS = LEGACY_FORMAT_TO_COLOR.values() .stream() - .collect(ImmutableMap.toImmutableMap(textColor -> textColor.name, Function.identity())); + .collect(ImmutableMap.toImmutableMap(e -> e.name, Function.identity())); private final int value; public final @Nullable String name; + // CraftBukkit start + @Nullable + public final ChatFormatting format; -- private TextColor(int value, String name) { -+ private TextColor(int value, String name, ChatFormatting format) { +- private TextColor(final int value, final String name) { ++ private TextColor(final int value, final String name, ChatFormatting format) { this.value = value & 16777215; this.name = name; + this.format = format; } - private TextColor(int value) { + private TextColor(final int value) { this.value = value & 16777215; this.name = null; + this.format = null; diff --git a/paper-server/patches/sources/net/minecraft/network/chat/contents/NbtContents.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/contents/NbtContents.java.patch index ca177c9cdd7f..e18f4e57cae7 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/contents/NbtContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/contents/NbtContents.java.patch @@ -1,20 +1,11 @@ --- a/net/minecraft/network/chat/contents/NbtContents.java +++ b/net/minecraft/network/chat/contents/NbtContents.java -@@ -118,7 +_,7 @@ +@@ -70,7 +_,7 @@ + } + }); + Component resolvedSeparator = DataFixUtils.orElse( +- ComponentUtils.resolve(context, this.separator, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR ++ ComponentUtils.resolveSeparator(context, this.separator, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator + ); if (this.interpreting) { RegistryOps registryOps = source.registryAccess().createSerializationContext(NbtOps.INSTANCE); - Component component = DataFixUtils.orElse( -- ComponentUtils.updateForEntity(source, this.separator, entity, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR -+ ComponentUtils.updateSeparatorForEntity(source, this.separator, entity, recursionDepth), ComponentUtils.DEFAULT_NO_STYLE_SEPARATOR // Paper - validate separator - ); - return stream.flatMap(tag -> { - try { -@@ -131,7 +_,7 @@ - }).reduce((mutableComponent, component1) -> mutableComponent.append(component).append(component1)).orElseGet(Component::empty); - } else { - Stream stream1 = stream.map(NbtContents::asString); -- return ComponentUtils.updateForEntity(source, this.separator, entity, recursionDepth) -+ return ComponentUtils.updateSeparatorForEntity(source, this.separator, entity, recursionDepth) // Paper - validate separator - .map( - mutableComponent -> stream1.map(Component::literal) - .reduce((mutableComponent1, otherMutableComponent) -> mutableComponent1.append(mutableComponent).append(otherMutableComponent)) diff --git a/paper-server/patches/sources/net/minecraft/network/chat/contents/ObjectContents.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/contents/ObjectContents.java.patch new file mode 100644 index 000000000000..dbe317a5b0e4 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/contents/ObjectContents.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/network/chat/contents/ObjectContents.java ++++ b/net/minecraft/network/chat/contents/ObjectContents.java +@@ -32,7 +_,7 @@ + + @Override + public MutableComponent resolve(final ResolutionContext context, final int recursionDepth) throws CommandSyntaxException { +- Optional fallback = ComponentUtils.resolve(context, this.fallback, recursionDepth); ++ Optional fallback = ComponentUtils.resolveSeparator(context, this.fallback, recursionDepth); // Paper - validate separator + ObjectInfo validatedContents = context.validate(this.contents); + return validatedContents == null + ? fallback.orElseGet(() -> Component.literal(this.contents.defaultFallback())) diff --git a/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch index 596e6f42a82a..d7fd00d307ee 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/network/chat/contents/SelectorContents.java +++ b/net/minecraft/network/chat/contents/SelectorContents.java -@@ -35,7 +_,7 @@ +@@ -37,7 +_,7 @@ if (source == null) { return Component.empty(); } else { -- Optional optional = ComponentUtils.updateForEntity(source, this.separator, entity, recursionDepth); -+ Optional optional = ComponentUtils.updateSeparatorForEntity(source, this.separator, entity, recursionDepth); // Paper - validate separator - return ComponentUtils.formatList(this.selector.resolved().findEntities(source), optional, Entity::getDisplayName); +- Optional resolvedSeparator = ComponentUtils.resolve(context, this.separator, recursionDepth); ++ Optional resolvedSeparator = ComponentUtils.resolveSeparator(context, this.separator, recursionDepth); // Paper - validate separator + return ComponentUtils.formatList(this.selector.compiled().findEntities(source), resolvedSeparator, Entity::getDisplayName); } } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/contents/TranslatableContents.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/contents/TranslatableContents.java.patch index bdbfe1fcb029..d93ab456914e 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/contents/TranslatableContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/contents/TranslatableContents.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/network/chat/contents/TranslatableContents.java +++ b/net/minecraft/network/chat/contents/TranslatableContents.java -@@ -178,6 +_,16 @@ +@@ -177,6 +_,16 @@ @Override - public Optional visit(FormattedText.ContentConsumer contentConsumer) { + public Optional visit(final FormattedText.ContentConsumer output) { + // Paper start - Count visited parts + try { -+ return this.visit(new TranslatableContentConsumer<>(contentConsumer)); ++ return this.visit(new TranslatableContentConsumer<>(output)); + } catch (IllegalArgumentException ignored) { -+ return contentConsumer.accept("..."); ++ return output.accept("..."); + } + } + -+ private Optional visit(TranslatableContentConsumer contentConsumer) { ++ private Optional visit(TranslatableContentConsumer output) { + // Paper end - Count visited parts this.decompose(); - for (FormattedText formattedText : this.decomposedParts) { -@@ -189,6 +_,27 @@ + for (FormattedText part : this.decomposedParts) { +@@ -188,6 +_,27 @@ return Optional.empty(); } @@ -44,4 +44,4 @@ + // Paper end - Count visited parts @Override - public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity entity, int recursionDepth) throws CommandSyntaxException { + public MutableComponent resolve(final ResolutionContext context, final int recursionDepth) throws CommandSyntaxException { diff --git a/paper-server/patches/sources/net/minecraft/network/codec/ByteBufCodecs.java.patch b/paper-server/patches/sources/net/minecraft/network/codec/ByteBufCodecs.java.patch index 6d8633da13b2..277fd8af4d1b 100644 --- a/paper-server/patches/sources/net/minecraft/network/codec/ByteBufCodecs.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/codec/ByteBufCodecs.java.patch @@ -46,6 +46,6 @@ + } + // Paper end - Track codec depth + - static StreamCodec> optional(final StreamCodec codec) { + static StreamCodec> optional(final StreamCodec original) { return new StreamCodec>() { @Override diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/Packet.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/Packet.java.patch index 221a5587d372..003903558f20 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/Packet.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/Packet.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/network/protocol/Packet.java @@ -11,6 +_,19 @@ - void handle(T handler); + void handle(T listener); + // Paper start + default boolean hasLargePacketFallback() { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java.patch index 10835a1af317..4bf443aa3d21 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java.patch @@ -4,7 +4,7 @@ private static final int MAX_PAYLOAD_SIZE = 32767; public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec( id -> DiscardedPayload.codec(id, 32767), -- Util.make(Lists.newArrayList(new CustomPacketPayload.TypeAndCodec<>(BrandPayload.TYPE, BrandPayload.STREAM_CODEC)), list -> {}) +- Util.make(Lists.newArrayList(new CustomPacketPayload.TypeAndCodec<>(BrandPayload.TYPE, BrandPayload.STREAM_CODEC)), types -> {}) + java.util.Collections.emptyList() // CraftBukkit - treat all packets the same ) .map(ServerboundCustomPayloadPacket::new, ServerboundCustomPayloadPacket::payload); diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/common/custom/DiscardedPayload.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/common/custom/DiscardedPayload.java.patch index 59f5e69f5568..29719bd22644 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/common/custom/DiscardedPayload.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/common/custom/DiscardedPayload.java.patch @@ -6,21 +6,21 @@ -public record DiscardedPayload(Identifier id) implements CustomPacketPayload { +public record DiscardedPayload(Identifier id, byte[] data) implements CustomPacketPayload { // Paper - store data - public static StreamCodec codec(Identifier id, int maxSize) { -- return CustomPacketPayload.codec((value, output) -> {}, buffer -> { -+ return CustomPacketPayload.codec((value, output) -> { + public static StreamCodec codec(final Identifier id, final int maxPayloadSize) { +- return CustomPacketPayload.codec((payload, buf) -> {}, buf -> { ++ return CustomPacketPayload.codec((payload, buf) -> { + // Paper start + // Always write data -+ output.writeBytes(value.data); -+ }, buffer -> { - int i = buffer.readableBytes(); - if (i >= 0 && i <= maxSize) { -- buffer.skipBytes(i); ++ buf.writeBytes(payload.data); ++ }, buf -> { + int length = buf.readableBytes(); + if (length >= 0 && length <= maxPayloadSize) { +- buf.skipBytes(length); - return new DiscardedPayload(id); -+ final byte[] data = new byte[i]; -+ buffer.readBytes(data); ++ final byte[] data = new byte[length]; ++ buf.readBytes(data); + return new DiscardedPayload(id, data); + // Paper end } else { - throw new IllegalArgumentException("Payload may not be larger than " + maxSize + " bytes"); + throw new IllegalArgumentException("Payload may not be larger than " + maxPayloadSize + " bytes"); } diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java.patch index 92492a6835d3..72a2a17526a3 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java +++ b/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java -@@ -29,7 +_,7 @@ - - public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity, BiFunction dataGetter) { +@@ -31,7 +_,7 @@ + final BlockEntity blockEntity, final BiFunction updateTagSaver + ) { RegistryAccess registryAccess = blockEntity.getLevel().registryAccess(); -- return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), dataGetter.apply(blockEntity, registryAccess)); -+ return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), blockEntity.sanitizeSentNbt(dataGetter.apply(blockEntity, registryAccess))); // Paper - Sanitize sent data +- return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), updateTagSaver.apply(blockEntity, registryAccess)); ++ return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), blockEntity.sanitizeSentNbt(updateTagSaver.apply(blockEntity, registryAccess))); // Paper - Sanitize sent data } - public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity) { + public static ClientboundBlockEntityDataPacket create(final BlockEntity blockEntity) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java.patch index 03d18f0dc288..c2c9fc143be9 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -50,7 +_,7 @@ - public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf buffer, int x, int z) { - this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(buffer); - int varInt = buffer.readVarInt(); -- if (varInt > 2097152) { -+ if (varInt > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder + public ClientboundLevelChunkPacketData(final RegistryFriendlyByteBuf input, final int x, final int z) { + this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(input); + int size = input.readVarInt(); +- if (size > 2097152) { ++ if (size > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); } else { - this.buffer = new byte[varInt]; + this.buffer = new byte[size]; @@ -154,6 +_,7 @@ - CompoundTag updateTag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess()); - BlockPos blockPos = blockEntity.getBlockPos(); - int i = SectionPos.sectionRelative(blockPos.getX()) << 4 | SectionPos.sectionRelative(blockPos.getZ()); -+ blockEntity.sanitizeSentNbt(updateTag); // Paper - Sanitize sent data - return new ClientboundLevelChunkPacketData.BlockEntityInfo(i, blockPos.getY(), blockEntity.getType(), updateTag.isEmpty() ? null : updateTag); + CompoundTag tag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess()); + BlockPos pos = blockEntity.getBlockPos(); + int xz = SectionPos.sectionRelative(pos.getX()) << 4 | SectionPos.sectionRelative(pos.getZ()); ++ blockEntity.sanitizeSentNbt(tag); // Paper - Sanitize sent data + return new ClientboundLevelChunkPacketData.BlockEntityInfo(xz, pos.getY(), blockEntity.getType(), tag.isEmpty() ? null : tag); } } diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java.patch index edcd2a2d5de7..e1c2d8ad9c30 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java.patch @@ -10,5 +10,5 @@ + } + // Paper end - Anti-Xray - public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight) { - ChunkPos pos = chunk.getPos(); + public ClientboundLevelChunkWithLightPacket( + final LevelChunk levelChunk, diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java.patch index bed45c045c4a..20051a27a9e1 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java.patch @@ -16,11 +16,11 @@ + } + // Paper end - Add Listing API for Player - public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection players) { - EnumSet set = EnumSet.of( + public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(final Collection players) { + EnumSet actions = EnumSet.of( @@ -53,6 +_,46 @@ ); - return new ClientboundPlayerInfoUpdatePacket(set, players); + return new ClientboundPlayerInfoUpdatePacket(actions, players); } + // Paper start - Add Listing API for Player + public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection players, ServerPlayer forPlayer) { @@ -63,33 +63,33 @@ + } + // Paper end - Add Listing API for Player - private ClientboundPlayerInfoUpdatePacket(RegistryFriendlyByteBuf buffer) { - this.actions = buffer.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class); + private ClientboundPlayerInfoUpdatePacket(final RegistryFriendlyByteBuf input) { + this.actions = input.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class); @@ -117,7 +_,15 @@ }), INITIALIZE_CHAT( - (entryBuilder, buffer) -> entryBuilder.chatSession = buffer.readNullable(RemoteChatSession.Data::read), -- (buffer, entry) -> buffer.writeNullable(entry.chatSession, RemoteChatSession.Data::write) + (entry, input) -> entry.chatSession = input.readNullable(RemoteChatSession.Data::read), +- (output, entry) -> output.writeNullable(entry.chatSession, RemoteChatSession.Data::write) + // Paper start - Prevent causing expired keys from impacting new joins -+ (buffer, entry) -> { ++ (output, entry) -> { + RemoteChatSession.Data chatSession = entry.chatSession; + if (chatSession != null && chatSession.profilePublicKey().hasExpired()) { + chatSession = null; + } -+ buffer.writeNullable(chatSession, RemoteChatSession.Data::write); ++ output.writeNullable(chatSession, RemoteChatSession.Data::write); + } + // Paper end - Prevent causing expired keys from impacting new joins ), - UPDATE_GAME_MODE( - (entryBuilder, buffer) -> entryBuilder.gameMode = GameType.byId(buffer.readVarInt()), -@@ -161,10 +_,15 @@ + UPDATE_GAME_MODE((entry, input) -> entry.gameMode = GameType.byId(input.readVarInt()), (output, entry) -> output.writeVarInt(entry.gameMode().getId())), + UPDATE_LISTED((entry, input) -> entry.listed = input.readBoolean(), (output, entry) -> output.writeBoolean(entry.listed())), +@@ -158,10 +_,15 @@ RemoteChatSession.@Nullable Data chatSession ) { - Entry(ServerPlayer player) { + private Entry(final ServerPlayer player) { + // Paper start - Add Listing API for Player + this(player, true); + } -+ Entry(ServerPlayer player, boolean listed) { ++ private Entry(ServerPlayer player, boolean listed) { this( + // Paper end - Add Listing API for Player player.getUUID(), @@ -99,7 +99,7 @@ player.connection.latency(), player.gameMode(), player.getTabListDisplayName(), -@@ -173,6 +_,11 @@ +@@ -170,6 +_,11 @@ Optionull.map(player.getChatSession(), RemoteChatSession::asData) ); } @@ -110,4 +110,4 @@ + // Paper end - Add Listing API for Player } - static class EntryBuilder { + private static class EntryBuilder { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java.patch index f73670c52257..0acf8c0f9cec 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java.patch @@ -1,11 +1,13 @@ --- a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +++ b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java -@@ -30,10 +_,25 @@ +@@ -30,12 +_,25 @@ - for (short s : positions) { - this.positions[i] = s; -- this.states[i] = section.getBlockState(SectionPos.sectionRelativeX(s), SectionPos.sectionRelativeY(s), SectionPos.sectionRelativeZ(s)); -+ this.states[i] = (section != null) ? section.getBlockState(SectionPos.sectionRelativeX(s), SectionPos.sectionRelativeY(s), SectionPos.sectionRelativeZ(s)) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(); // CraftBukkit - SPIGOT-6076, Mojang bug when empty chunk section notified + for (short packedPos : changes) { + this.positions[i] = packedPos; +- this.states[i] = section.getBlockState( +- SectionPos.sectionRelativeX(packedPos), SectionPos.sectionRelativeY(packedPos), SectionPos.sectionRelativeZ(packedPos) +- ); ++ this.states[i] = (section != null) ? section.getBlockState(SectionPos.sectionRelativeX(packedPos), SectionPos.sectionRelativeY(packedPos), SectionPos.sectionRelativeZ(packedPos)) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(); // CraftBukkit - SPIGOT-6076, Mojang bug when empty chunk section notified i++; } } @@ -25,5 +27,5 @@ + // Paper end - Multi Block Change API + - private ClientboundSectionBlocksUpdatePacket(FriendlyByteBuf buffer) { - this.sectionPos = SectionPos.STREAM_CODEC.decode(buffer); + private ClientboundSectionBlocksUpdatePacket(final FriendlyByteBuf input) { + this.sectionPos = SectionPos.STREAM_CODEC.decode(input); diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java.patch index f8353c254ea7..7c6aa304916c 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java.patch @@ -3,12 +3,12 @@ @@ -19,9 +_,11 @@ } - private static void pack(List> dataValues, RegistryFriendlyByteBuf buffer) { + private static void pack(final List> items, final RegistryFriendlyByteBuf output) { + try (io.papermc.paper.util.sanitizer.ItemObfuscationSession ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.start(io.papermc.paper.configuration.GlobalConfiguration.get().anticheat.obfuscation.items.binding.level)) { // Paper - data sanitization - for (SynchedEntityData.DataValue dataValue : dataValues) { - dataValue.write(buffer); + for (SynchedEntityData.DataValue item : items) { + item.write(output); } + } // Paper - data sanitization - buffer.writeByte(255); + output.writeByte(255); } diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java.patch index 1a8efdc47835..6f77ce833e58 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java.patch @@ -3,7 +3,7 @@ @@ -19,6 +_,13 @@ private final List> slots; - public ClientboundSetEquipmentPacket(int entity, List> slots) { + public ClientboundSetEquipmentPacket(final int entity, final List> slots) { + // Paper start - data sanitization + this(entity, slots, false); + } @@ -15,16 +15,16 @@ this.slots = slots; } @@ -40,6 +_,7 @@ - buffer.writeVarInt(this.entity); + output.writeVarInt(this.entity); int size = this.slots.size(); + try (final io.papermc.paper.util.sanitizer.ItemObfuscationSession ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.start(this.sanitize ? io.papermc.paper.configuration.GlobalConfiguration.get().anticheat.obfuscation.items.binding.level : io.papermc.paper.util.sanitizer.ItemObfuscationSession.ObfuscationLevel.NONE)) { // Paper - data sanitization for (int i = 0; i < size; i++) { - Pair pair = this.slots.get(i); - EquipmentSlot equipmentSlot = pair.getFirst(); + Pair e = this.slots.get(i); + EquipmentSlot slotType = e.getFirst(); @@ -48,6 +_,7 @@ - buffer.writeByte(flag ? ordinal | -128 : ordinal); - ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, pair.getSecond()); + output.writeByte(shouldContinue ? slotId | -128 : slotId); + ItemStack.OPTIONAL_STREAM_CODEC.encode(output, e.getSecond()); } + } // Paper - data sanitization } diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java.patch index dfa5bbbfebde..7e1cfcafd6e5 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java +++ b/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java -@@ -57,6 +_,12 @@ +@@ -61,6 +_,12 @@ ); } @@ -10,15 +10,15 @@ + } + // Paper end - Multiple Entries with Scoreboards + - private ClientboundSetPlayerTeamPacket(RegistryFriendlyByteBuf buffer) { - this.name = buffer.readUtf(); - this.method = buffer.readByte(); -@@ -197,7 +_,7 @@ - ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buffer, this.displayName); - buffer.writeByte(this.options); - Team.Visibility.STREAM_CODEC.encode(buffer, this.nametagVisibility); -- Team.CollisionRule.STREAM_CODEC.encode(buffer, this.collisionRule); -+ Team.CollisionRule.STREAM_CODEC.encode(buffer, !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? PlayerTeam.CollisionRule.NEVER : this.collisionRule); // Paper - Configurable player collision - buffer.writeEnum(this.color); - ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buffer, this.playerPrefix); - ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buffer, this.playerSuffix); + private ClientboundSetPlayerTeamPacket(final RegistryFriendlyByteBuf input) { + this.name = input.readUtf(); + this.method = input.readByte(); +@@ -201,7 +_,7 @@ + ComponentSerialization.TRUSTED_STREAM_CODEC.encode(output, this.displayName); + output.writeByte(this.options); + Team.Visibility.STREAM_CODEC.encode(output, this.nametagVisibility); +- Team.CollisionRule.STREAM_CODEC.encode(output, this.collisionRule); ++ Team.CollisionRule.STREAM_CODEC.encode(output, !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? PlayerTeam.CollisionRule.NEVER : this.collisionRule); // Paper - Configurable player collision + output.writeEnum(this.color); + ComponentSerialization.TRUSTED_STREAM_CODEC.encode(output, this.playerPrefix); + ComponentSerialization.TRUSTED_STREAM_CODEC.encode(output, this.playerSuffix); diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java.patch index b8a62f6e22f1..2e09a7eb3614 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java.patch @@ -9,9 +9,9 @@ ServerboundChatCommandPacket::write, ServerboundChatCommandPacket::new ); - private ServerboundChatCommandPacket(FriendlyByteBuf buffer) { -- this(buffer.readUtf()); -+ this(buffer.readUtf(MAX_CHAT_PACKET_INPUT_SIZE)); // Paper - limit chat command inputs + private ServerboundChatCommandPacket(final FriendlyByteBuf input) { +- this(input.readUtf()); ++ this(input.readUtf(MAX_CHAT_PACKET_INPUT_SIZE)); // Paper - limit chat command inputs } - private void write(FriendlyByteBuf buffer) { + private void write(final FriendlyByteBuf output) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java.patch index 0378ad997adf..f033ecd4998b 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java.patch @@ -3,9 +3,9 @@ @@ -16,7 +_,7 @@ ); - private ServerboundChatCommandSignedPacket(FriendlyByteBuf buffer) { -- this(buffer.readUtf(), buffer.readInstant(), buffer.readLong(), new ArgumentSignatures(buffer), new LastSeenMessages.Update(buffer)); -+ this(buffer.readUtf(net.minecraft.network.protocol.game.ServerboundChatCommandPacket.MAX_CHAT_PACKET_INPUT_SIZE), buffer.readInstant(), buffer.readLong(), new ArgumentSignatures(buffer), new LastSeenMessages.Update(buffer)); // Paper - limit chat command inputs + private ServerboundChatCommandSignedPacket(final FriendlyByteBuf input) { +- this(input.readUtf(), input.readInstant(), input.readLong(), new ArgumentSignatures(input), new LastSeenMessages.Update(input)); ++ this(input.readUtf(net.minecraft.network.protocol.game.ServerboundChatCommandPacket.MAX_CHAT_PACKET_INPUT_SIZE), input.readInstant(), input.readLong(), new ArgumentSignatures(input), new LastSeenMessages.Update(input)); // Paper - limit chat command inputs } - private void write(FriendlyByteBuf buffer) { + private void write(final FriendlyByteBuf output) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java.patch index 3161af31644d..a4cebb786e6a 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/network/protocol/game/ServerboundCommandSuggestionPacket.java @@ -19,7 +_,7 @@ - private ServerboundCommandSuggestionPacket(FriendlyByteBuf buffer) { - this.id = buffer.readVarInt(); -- this.command = buffer.readUtf(32500); -+ this.command = buffer.readUtf(2048); // Paper + private ServerboundCommandSuggestionPacket(final FriendlyByteBuf input) { + this.id = input.readVarInt(); +- this.command = input.readUtf(32500); ++ this.command = input.readUtf(2048); // Paper } - private void write(FriendlyByteBuf buffer) { + private void write(final FriendlyByteBuf output) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundInteractPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundInteractPacket.java.patch deleted file mode 100644 index 8d441064cbc2..000000000000 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundInteractPacket.java.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- a/net/minecraft/network/protocol/game/ServerboundInteractPacket.java -+++ b/net/minecraft/network/protocol/game/ServerboundInteractPacket.java -@@ -152,6 +_,15 @@ - buffer.writeEnum(this.hand); - } - } -+ // Paper start - PlayerUseUnknownEntityEvent -+ public int getEntityId() { -+ return this.entityId; -+ } -+ -+ public boolean isAttack() { -+ return this.action.getType() == ActionType.ATTACK; -+ } -+ // Paper end - PlayerUseUnknownEntityEvent - - static class InteractionAtLocationAction implements ServerboundInteractPacket.Action { - private final InteractionHand hand; diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemOnPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemOnPacket.java.patch index 73bc58e48b7d..bf89e2fdd266 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemOnPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemOnPacket.java.patch @@ -6,13 +6,13 @@ private final int sequence; + public long timestamp; // Spigot - public ServerboundUseItemOnPacket(InteractionHand hand, BlockHitResult blockHit, int sequence) { + public ServerboundUseItemOnPacket(final InteractionHand hand, final BlockHitResult blockHit, final int sequence) { this.hand = hand; @@ -22,6 +_,7 @@ } - private ServerboundUseItemOnPacket(FriendlyByteBuf buffer) { + private ServerboundUseItemOnPacket(final FriendlyByteBuf input) { + this.timestamp = System.currentTimeMillis(); // Spigot - this.hand = buffer.readEnum(InteractionHand.class); - this.blockHit = buffer.readBlockHitResult(); - this.sequence = buffer.readVarInt(); + this.hand = input.readEnum(InteractionHand.class); + this.blockHit = input.readBlockHitResult(); + this.sequence = input.readVarInt(); diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemPacket.java.patch index b4e853fe8272..1a9005b6f99a 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ServerboundUseItemPacket.java.patch @@ -6,13 +6,13 @@ private final float xRot; + public long timestamp; // Spigot - public ServerboundUseItemPacket(InteractionHand hand, int sequence, float yRot, float xRot) { + public ServerboundUseItemPacket(final InteractionHand hand, final int sequence, final float yRot, final float xRot) { this.hand = hand; @@ -23,6 +_,7 @@ } - private ServerboundUseItemPacket(FriendlyByteBuf buffer) { + private ServerboundUseItemPacket(final FriendlyByteBuf input) { + this.timestamp = System.currentTimeMillis(); // Spigot - this.hand = buffer.readEnum(InteractionHand.class); - this.sequence = buffer.readVarInt(); - this.yRot = buffer.readFloat(); + this.hand = input.readEnum(InteractionHand.class); + this.sequence = input.readVarInt(); + this.yRot = input.readFloat(); diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/VecDeltaCodec.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/VecDeltaCodec.java.patch index fff6b8efc429..ea746bc5758b 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/VecDeltaCodec.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/VecDeltaCodec.java.patch @@ -8,4 +8,4 @@ + public Vec3 base = Vec3.ZERO; // Paper @VisibleForTesting - static long encode(double value) { + static long encode(final double input) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch index 752d456ac240..200a4d0c8260 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch @@ -3,9 +3,9 @@ @@ -20,7 +_,7 @@ } - private ClientIntentionPacket(FriendlyByteBuf buffer) { -- this(buffer.readVarInt(), buffer.readUtf(255), buffer.readUnsignedShort(), ClientIntent.byId(buffer.readVarInt())); -+ this(buffer.readVarInt(), buffer.readUtf(Short.MAX_VALUE), buffer.readUnsignedShort(), ClientIntent.byId(buffer.readVarInt())); // Spigot - increase max hostName length + private ClientIntentionPacket(final FriendlyByteBuf input) { +- this(input.readVarInt(), input.readUtf(255), input.readUnsignedShort(), ClientIntent.byId(input.readVarInt())); ++ this(input.readVarInt(), input.readUtf(Short.MAX_VALUE), input.readUnsignedShort(), ClientIntent.byId(input.readVarInt())); // Spigot - increase max hostName length } - private void write(FriendlyByteBuf buffer) { + private void write(final FriendlyByteBuf output) { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java.patch index d8ce01b3e11d..fb51d23533d6 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java +++ b/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java @@ -47,4 +_,13 @@ - public void handle(ClientLoginPacketListener handler) { - handler.handleCustomQuery(this); + public void handle(final ClientLoginPacketListener listener) { + listener.handleCustomQuery(this); } + + // Paper start - MC Utils - default query payloads diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java.patch index 40b8fdbc7893..77a76de19a0e 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java.patch @@ -3,10 +3,10 @@ @@ -20,7 +_,17 @@ } - private static CustomQueryAnswerPayload readPayload(int transactionId, FriendlyByteBuf buffer) { -- return readUnknownPayload(buffer); + private static CustomQueryAnswerPayload readPayload(final int transactionId, final FriendlyByteBuf input) { +- return readUnknownPayload(input); + // Paper start - MC Utils - default query payloads -+ FriendlyByteBuf buf = buffer.readNullable((buf2) -> { ++ FriendlyByteBuf buf = input.readNullable((buf2) -> { + int readableBytes = buf2.readableBytes(); + if (readableBytes >= 0 && readableBytes <= MAX_PAYLOAD_SIZE) { + return new FriendlyByteBuf(buf2.readBytes(readableBytes)); @@ -14,14 +14,14 @@ + throw new IllegalArgumentException("Payload may not be larger than " + MAX_PAYLOAD_SIZE + " bytes"); + } + }); -+ return buf == null ? null : new net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket.QueryAnswerPayload(buf); ++ return buf == null ? null : new QueryAnswerPayload(buf); + // Paper end - MC Utils - default query payloads } - private static CustomQueryAnswerPayload readUnknownPayload(FriendlyByteBuf buffer) { + private static CustomQueryAnswerPayload readUnknownPayload(final FriendlyByteBuf input) { @@ -47,4 +_,19 @@ - public void handle(ServerLoginPacketListener handler) { - handler.handleCustomQueryPacket(this); + public void handle(final ServerLoginPacketListener listener) { + listener.handleCustomQueryPacket(this); } + + // Paper start - MC Utils - default query payloads diff --git a/paper-server/patches/sources/net/minecraft/network/syncher/EntityDataSerializers.java.patch b/paper-server/patches/sources/net/minecraft/network/syncher/EntityDataSerializers.java.patch index 24afdbddedb8..178e2bd1e79a 100644 --- a/paper-server/patches/sources/net/minecraft/network/syncher/EntityDataSerializers.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/syncher/EntityDataSerializers.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/syncher/EntityDataSerializers.java +++ b/net/minecraft/network/syncher/EntityDataSerializers.java -@@ -55,10 +_,27 @@ +@@ -59,10 +_,27 @@ public static final EntityDataSerializer> OPTIONAL_COMPONENT = EntityDataSerializer.forValueType( ComponentSerialization.TRUSTED_OPTIONAL_STREAM_CODEC ); diff --git a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch index d94f74eb7226..33c19095a735 100644 --- a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch @@ -5,8 +5,8 @@ } + // CraftBukkit start - add method from above -+ public void markDirty(final EntityDataAccessor entityDataAccessor) { -+ this.getItem(entityDataAccessor).setDirty(true); ++ public void markDirty(final EntityDataAccessor accessor) { ++ this.getItem(accessor).setDirty(true); + this.isDirty = true; + } + // CraftBukkit end @@ -23,14 +23,14 @@ + // We need to pack all as we cannot rely on "non default values" or "dirty" ones. + // Because these values can possibly be desynced on the client. + public List> packAll() { -+ final List> list = new ArrayList<>(this.itemsById.length); -+ for (final DataItem dataItem : this.itemsById) { -+ list.add(dataItem.value()); ++ final List> values = new ArrayList<>(this.itemsById.length); ++ for (final DataItem item : this.itemsById) { ++ values.add(item.value()); + } + -+ return list; ++ return values; + } + // Paper end public static class DataItem { - final EntityDataAccessor accessor; + private final EntityDataAccessor accessor; diff --git a/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch b/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch index 23ea05ccf452..592a39a552a9 100644 --- a/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch @@ -1,39 +1,39 @@ --- a/net/minecraft/resources/Identifier.java +++ b/net/minecraft/resources/Identifier.java -@@ -20,6 +_,7 @@ - public static final char NAMESPACE_SEPARATOR = ':'; +@@ -22,6 +_,7 @@ public static final String DEFAULT_NAMESPACE = "minecraft"; public static final String REALMS_NAMESPACE = "realms"; + public static final String ALLOWED_NAMESPACE_CHARACTERS = "[a-z0-9_.-]"; + public static final String PAPER_NAMESPACE = "paper"; // Paper private final String namespace; private final String path; -@@ -28,6 +_,13 @@ +@@ -30,6 +_,13 @@ assert isValidPath(path); + // Paper start - Validate Identifier + // Check for the max network string length (capped at Short.MAX_VALUE) as well as the max bytes of a StringTag (length written as an unsigned short) -+ final String resourceLocation = namespace + ":" + path; -+ if (resourceLocation.length() > Short.MAX_VALUE || io.netty.buffer.ByteBufUtil.utf8MaxBytes(resourceLocation) > 2 * Short.MAX_VALUE + 1) { -+ throw new IdentifierException("Resource location too long: " + resourceLocation); ++ final String id = namespace + ":" + path; ++ if (id.length() > Short.MAX_VALUE || io.netty.buffer.ByteBufUtil.utf8MaxBytes(id) > 2 * Short.MAX_VALUE + 1) { ++ throw new IdentifierException("Identifier too long: " + id); + } + // Paper end - Validate Identifier this.namespace = namespace; this.path = path; } -@@ -238,7 +_,7 @@ +@@ -242,7 +_,7 @@ - private static String assertValidNamespace(String namespace, String path) { + private static String assertValidNamespace(final String namespace, final String path) { if (!isValidNamespace(namespace)) { -- throw new IdentifierException("Non [a-z0-9_.-] character in namespace of location: " + namespace + ":" + path); -+ throw new IdentifierException("Non [a-z0-9_.-] character in namespace of location: " + org.apache.commons.lang3.StringUtils.normalizeSpace(namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize Identifier error logging +- throw new IdentifierException("Non [a-z0-9_.-] character in namespace of identifier: " + namespace + ":" + path); ++ throw new IdentifierException("Non [a-z0-9_.-] character in namespace of identifier: " + org.apache.commons.lang3.StringUtils.normalizeSpace(namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize Identifier error logging } else { return namespace; } -@@ -263,7 +_,7 @@ +@@ -258,7 +_,7 @@ - private static String assertValidPath(String namespace, String path) { + private static String assertValidPath(final String namespace, final String path) { if (!isValidPath(path)) { - throw new IdentifierException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path); + throw new IdentifierException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize Identifier error logging diff --git a/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch b/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch new file mode 100644 index 000000000000..2f7996f97cc3 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/resources/NetworkRegistryLoadTask.java ++++ b/net/minecraft/resources/NetworkRegistryLoadTask.java +@@ -79,7 +_,7 @@ + } + + return Util.sequence(elements).thenAcceptAsync(pendingRegistrations -> { +- this.registerElements(pendingRegistrations.stream()); ++ this.registerElements(pendingRegistrations.stream(), null); // Paper - this code is only used on the client + Map, List>> pendingTags = TagLoader.loadTagsFromNetwork(registryEntries.tags(), this.readOnlyRegistry()); + this.registerTags(pendingTags); + }, executor); diff --git a/paper-server/patches/sources/net/minecraft/resources/RegistryDataLoader.java.patch b/paper-server/patches/sources/net/minecraft/resources/RegistryDataLoader.java.patch index 5776d719e9a2..91fa2b5938bb 100644 --- a/paper-server/patches/sources/net/minecraft/resources/RegistryDataLoader.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/RegistryDataLoader.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/resources/RegistryDataLoader.java +++ b/net/minecraft/resources/RegistryDataLoader.java -@@ -212,11 +_,21 @@ - final Map>, RegistryOps.RegistryInfo> map = new HashMap<>(); - registryLookups.forEach(registryLookup -> map.put(registryLookup.key(), createInfoForContextRegistry((HolderLookup.RegistryLookup)registryLookup))); - loaders.forEach(loader -> map.put(loader.registry.key(), createInfoForNewRegistry(loader.registry))); +@@ -243,11 +_,21 @@ + final Map>, RegistryOps.RegistryInfo> result = new HashMap<>(); + contextRegistries.forEach(e -> result.put(e.key(), createInfoForContextRegistry((HolderLookup.RegistryLookup)e))); + newRegistriesAndLoaders.forEach(e -> result.put(e.registryKey(), e.createRegistryInfo())); + // this creates a HolderLookup.Provider to be used exclusively to obtain real instances of values to pre-populate builders + // for the Registry Modification API. This concatenates the context registry lookups and the empty registries about to be filled. -+ final HolderLookup.Provider providerForBuilders = HolderLookup.Provider.create(java.util.stream.Stream.concat(registryLookups.stream(), loaders.stream().map(Loader::registry))); // Paper - add method to get the value for pre-filling builders in the reg mod API ++ final HolderLookup.Provider providerForBuilders = HolderLookup.Provider.create(java.util.stream.Stream.concat(contextRegistries.stream(), newRegistriesAndLoaders.stream().map(t -> t.registry))); // Paper - add method to get the value for pre-filling builders in the reg mod API return new RegistryOps.RegistryInfoLookup() { @Override - public Optional> lookup(ResourceKey> registryKey) { - return Optional.ofNullable((RegistryOps.RegistryInfo)map.get(registryKey)); + public Optional> lookup(final ResourceKey> key) { + return Optional.ofNullable((RegistryOps.RegistryInfo)result.get(key)); } + + // Paper start - add method to get the value for pre-filling builders in the reg mod API @@ -22,73 +22,3 @@ }; } -@@ -280,13 +_,14 @@ - RegistryOps ops, - ResourceKey resourceKey, - Resource resource, -- RegistrationInfo registrationInfo -+ RegistrationInfo registrationInfo, -+ io.papermc.paper.registry.data.util.Conversions conversions // Paper - pass conversions - ) throws IOException { - try (Reader reader = resource.openAsReader()) { - JsonElement jsonElement = StrictJsonParser.parse(reader); - DataResult dataResult = codec.parse(ops, jsonElement); - E orThrow = dataResult.getOrThrow(); -- registry.register(resourceKey, orThrow, registrationInfo); -+ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(registry, resourceKey, orThrow, registrationInfo, conversions); // Paper - register with listeners - } - } - -@@ -300,6 +_,7 @@ - FileToIdConverter fileToIdConverter = FileToIdConverter.registry(registry.key()); - RegistryOps registryOps = RegistryOps.create(JsonOps.INSTANCE, registryInfoLookup); - -+ final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(registryInfoLookup); // Paper - create conversions - for (Entry entry : fileToIdConverter.listMatchingResources(resourceManager).entrySet()) { - Identifier identifier = entry.getKey(); - ResourceKey resourceKey = ResourceKey.create(registry.key(), fileToIdConverter.fileToId(identifier)); -@@ -307,7 +_,7 @@ - RegistrationInfo registrationInfo = REGISTRATION_INFO_CACHE.apply(resource.knownPackInfo()); - - try { -- loadElementFromResource(registry, codec, registryOps, resourceKey, resource, registrationInfo); -+ loadElementFromResource(registry, codec, registryOps, resourceKey, resource, registrationInfo, conversions); // Paper - pass conversions - } catch (Exception var14) { - loadingErrors.put( - resourceKey, -@@ -316,7 +_,9 @@ - } - } - -- TagLoader.loadTagsForRegistry(resourceManager, registry); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(registry.key()); // Paper - lock reference holders -+ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key(), conversions); // Paper - run pre-freeze listeners -+ TagLoader.loadTagsForRegistry(resourceManager, registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - tag lifecycle - add cause - } - - static void loadContentsFromNetwork( -@@ -333,6 +_,7 @@ - RegistryOps registryOps1 = RegistryOps.create(JsonOps.INSTANCE, registryInfoLookup); - FileToIdConverter fileToIdConverter = FileToIdConverter.registry(registry.key()); - -+ final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(registryInfoLookup); // Paper - create conversions - for (RegistrySynchronization.PackedRegistryEntry packedRegistryEntry : networkedRegistryData.elements) { - ResourceKey resourceKey = ResourceKey.create(registry.key(), packedRegistryEntry.id()); - Optional optional = packedRegistryEntry.data(); -@@ -351,7 +_,7 @@ - - try { - Resource resourceOrThrow = resourceProvider.getResourceOrThrow(identifier); -- loadElementFromResource(registry, codec, registryOps1, resourceKey, resourceOrThrow, NETWORK_REGISTRATION_INFO); -+ loadElementFromResource(registry, codec, registryOps1, resourceKey, resourceOrThrow, NETWORK_REGISTRATION_INFO, conversions); // Paper - pass conversions - } catch (Exception var17) { - loadingErrors.put(resourceKey, new IllegalStateException("Failed to parse local data", var17)); - } -@@ -393,6 +_,7 @@ - - RegistryDataLoader.Loader create(Lifecycle registryLifecycle, Map, Exception> loadingErrors) { - WritableRegistry writableRegistry = new MappedRegistry<>(this.key, registryLifecycle); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(writableRegistry); // Paper - initialize API registry - return new RegistryDataLoader.Loader<>(this, writableRegistry, loadingErrors); - } - diff --git a/paper-server/patches/sources/net/minecraft/resources/RegistryLoadTask.java.patch b/paper-server/patches/sources/net/minecraft/resources/RegistryLoadTask.java.patch new file mode 100644 index 000000000000..3077800843e8 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/resources/RegistryLoadTask.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/resources/RegistryLoadTask.java ++++ b/net/minecraft/resources/RegistryLoadTask.java +@@ -29,7 +_,7 @@ + public abstract class RegistryLoadTask { + private final Object registryWriteLock = new Object(); + protected final RegistryDataLoader.RegistryData data; +- private final WritableRegistry registry; ++ final WritableRegistry registry; // Paper - package-private + protected final ConcurrentHolderGetter concurrentRegistrationGetter; + protected final Map, Exception> loadingErrors; + private volatile boolean elementsRegistered; +@@ -39,6 +_,7 @@ + this.registry = new MappedRegistry<>(data.key(), lifecycle); + this.loadingErrors = loadingErrors; + this.concurrentRegistrationGetter = new ConcurrentHolderGetter<>(this.registryWriteLock, this.registry.createRegistrationLookup()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(this.registry); // Paper - initialize API registry + } + + protected ResourceKey> registryKey() { +@@ -59,11 +_,11 @@ + return new RegistryOps.RegistryInfo<>(this.registry, this.concurrentRegistrationGetter, this.registry.registryLifecycle()); + } + +- protected void registerElements(final Stream> elements) { ++ protected void registerElements(final Stream> elements, final io.papermc.paper.registry.data.util.Conversions conversions) { // Paper - pass conversions + synchronized (this.registryWriteLock) { + elements.forEach( + element -> element.value +- .ifLeft(value -> this.registry.register(element.key, (T)value, element.registrationInfo)) ++ .ifLeft(value -> io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(this.registry, element.key, (T)value, element.registrationInfo, conversions)) // Paper - register with listeners + .ifRight(error -> this.loadingErrors.put(element.key, error)) + ); + this.elementsRegistered = true; diff --git a/paper-server/patches/sources/net/minecraft/resources/RegistryOps.java.patch b/paper-server/patches/sources/net/minecraft/resources/RegistryOps.java.patch index 93b5b31807ba..031749c949c6 100644 --- a/paper-server/patches/sources/net/minecraft/resources/RegistryOps.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/RegistryOps.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/resources/RegistryOps.java +++ b/net/minecraft/resources/RegistryOps.java -@@ -117,6 +_,13 @@ +@@ -116,6 +_,13 @@ public int hashCode() { return this.lookupProvider.hashCode(); } @@ -14,7 +14,7 @@ } public record RegistryInfo(HolderOwner owner, HolderGetter getter, Lifecycle elementsLifecycle) { -@@ -127,5 +_,7 @@ +@@ -126,5 +_,7 @@ public interface RegistryInfoLookup { Optional> lookup(ResourceKey> registryKey); diff --git a/paper-server/patches/sources/net/minecraft/resources/ResourceManagerRegistryLoadTask.java.patch b/paper-server/patches/sources/net/minecraft/resources/ResourceManagerRegistryLoadTask.java.patch new file mode 100644 index 000000000000..17f57ea24dad --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/resources/ResourceManagerRegistryLoadTask.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/resources/ResourceManagerRegistryLoadTask.java ++++ b/net/minecraft/resources/ResourceManagerRegistryLoadTask.java +@@ -40,6 +_,7 @@ + @Override + public CompletableFuture load(final RegistryOps.RegistryInfoLookup context, final Executor executor) { + FileToIdConverter lister = FileToIdConverter.registry(this.registryKey()); ++ final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(context); // Paper - create conversions + return CompletableFuture.>supplyAsync(() -> lister.listMatchingResources(this.resourceManager), executor) + .thenCompose( + registryResources -> { +@@ -61,11 +_,13 @@ + ) + .thenAcceptAsync( + loadedEntries -> { +- this.registerElements(loadedEntries.entrySet().stream().sorted(Entry.comparingByKey()).map(Entry::getValue)); ++ this.registerElements(loadedEntries.entrySet().stream().sorted(Entry.comparingByKey()).map(Entry::getValue), conversions); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(this.registryKey()); // Paper - lock reference holders ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(this.registryKey(), conversions); // Paper - run pre-freeze listeners + TagLoader.ElementLookup> tagElementLookup = TagLoader.ElementLookup.fromGetters( + this.registryKey(), this.concurrentRegistrationGetter, this.readOnlyRegistry() + ); +- Map, List>> pendingTags = TagLoader.loadTagsForRegistry(this.resourceManager, this.registryKey(), tagElementLookup); ++ Map, List>> pendingTags = TagLoader.loadTagsForRegistry(this.resourceManager, this.registryKey(), tagElementLookup, this.registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - tag lifecycle - add registry, cause + this.registerTags(pendingTags); + }, + executor diff --git a/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch b/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch index 2700e1f082b5..89768f069023 100644 --- a/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch @@ -3,7 +3,7 @@ @@ -43,6 +_,7 @@ if (!isBootstrapped) { isBootstrapped = true; - Instant instant = Instant.now(); + Instant start = Instant.now(); + io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping if (BuiltInRegistries.REGISTRY.keySet().isEmpty()) { throw new IllegalStateException("Unable to load registries"); @@ -11,7 +11,7 @@ @@ -54,11 +_,85 @@ EntitySelectorOptions.bootStrap(); DispenseItemBehavior.bootStrap(); - CauldronInteraction.bootStrap(); + CauldronInteractions.bootStrap(); - BuiltInRegistries.bootStrap(); + // Paper start + BuiltInRegistries.bootStrap(() -> { @@ -20,7 +20,7 @@ + // Paper end CreativeModeTabs.validate(); wrapStreams(); - bootstrapDuration.set(Duration.between(instant, Instant.now()).toMillis()); + bootstrapDuration.set(Duration.between(start, Instant.now()).toMillis()); } + // CraftBukkit start + // TODO Check what of this is needed, maybe report it to Mojira. if deemed relevant, move to the respective classes diff --git a/paper-server/patches/sources/net/minecraft/server/Main.java.patch b/paper-server/patches/sources/net/minecraft/server/Main.java.patch index 261d5d355c1c..5f7352813568 100644 --- a/paper-server/patches/sources/net/minecraft/server/Main.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/Main.java.patch @@ -1,67 +1,67 @@ --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java -@@ -64,8 +_,10 @@ +@@ -63,8 +_,10 @@ + private static final Logger LOGGER = LogUtils.getLogger(); @SuppressForbidden(reason = "System.out needed before bootstrap") - @DontObfuscate -- public static void main(String[] args) { -+ public static void main(final OptionSet optionSet) { // CraftBukkit - replaces main(String[] args) +- public static void main(final String[] args) { ++ public static void main(final OptionSet options) { // CraftBukkit - replaces main(String[] args) + io.papermc.paper.log.LogManagerShutdownThread.hook(); // Paper - Improved watchdog support SharedConstants.tryDetectVersion(); + /* CraftBukkit start - Replace everything - OptionParser optionParser = new OptionParser(); - OptionSpec optionSpec = optionParser.accepts("nogui"); - OptionSpec optionSpec1 = optionParser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits"); -@@ -90,41 +_,94 @@ - optionParser.printHelpOn(System.err); + OptionParser parser = new OptionParser(); + OptionSpec nogui = parser.accepts("nogui"); + OptionSpec initSettings = parser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits"); +@@ -89,41 +_,94 @@ + parser.printHelpOn(System.err); return; } + */ // CraftBukkit end + try { -- Path path = optionSet.valueOf(optionSpec14); -+ Path path = (Path) optionSet.valueOf("pidFile"); // CraftBukkit - if (path != null) { - writePidFile(path); +- Path pidFilePath = options.valueOf(pidFile); ++ Path pidFilePath = (Path) options.valueOf("pidFile"); // CraftBukkit + if (pidFilePath != null) { + writePidFile(pidFilePath); } CrashReport.preload(); -- if (optionSet.has(optionSpec13)) { -+ if (optionSet.has("jfrProfile")) { // CraftBukkit +- if (options.has(jfrProfilingOption)) { ++ if (options.has("jfrProfile")) { // CraftBukkit JvmProfiler.INSTANCE.start(Environment.SERVER); } -+ io.papermc.paper.plugin.PluginInitializerManager.load(optionSet); // Paper ++ io.papermc.paper.plugin.PluginInitializerManager.load(options); // Paper Bootstrap.bootStrap(); Bootstrap.validate(); Util.startTimerHackThread(); - Path path1 = Paths.get("server.properties"); -- DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(path1); -+ DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support - dedicatedServerSettings.forceSave(); - RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); - Path path2 = Paths.get("eula.txt"); - Eula eula = new Eula(path2); -- if (optionSet.has(optionSpec1)) { + Path settingsFile = Paths.get("server.properties"); +- DedicatedServerSettings settings = new DedicatedServerSettings(settingsFile); ++ DedicatedServerSettings settings = new DedicatedServerSettings(options); // CraftBukkit - CLI argument support + settings.forceSave(); + RegionFileVersion.configure(settings.getProperties().regionFileComression); + Path eulaFile = Paths.get("eula.txt"); + Eula eula = new Eula(eulaFile); +- if (options.has(initSettings)) { + // Paper start - load config files early for access below if needed -+ org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("bukkit-settings")); -+ org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings")); ++ org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) options.valueOf("bukkit-settings")); ++ org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) options.valueOf("spigot-settings")); + // Paper end - load config files early for access below if needed -+ if (optionSet.has("initSettings")) { // CraftBukkit ++ if (options.has("initSettings")) { // CraftBukkit + // CraftBukkit start - SPIGOT-5761: Create bukkit.yml and commands.yml if not present -+ File configFile = (File) optionSet.valueOf("bukkit-settings"); ++ File configFile = (File) options.valueOf("bukkit-settings"); + org.bukkit.configuration.file.YamlConfiguration configuration = org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(configFile); + configuration.options().copyDefaults(true); + configuration.setDefaults(org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(new java.io.InputStreamReader(Main.class.getClassLoader().getResourceAsStream("configurations/bukkit.yml"), java.nio.charset.StandardCharsets.UTF_8))); + configuration.save(configFile); + -+ File commandFile = (File) optionSet.valueOf("commands-settings"); ++ File commandFile = (File) options.valueOf("commands-settings"); + org.bukkit.configuration.file.YamlConfiguration commandsConfiguration = org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(commandFile); + commandsConfiguration.options().copyDefaults(true); + commandsConfiguration.setDefaults(org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(new java.io.InputStreamReader(Main.class.getClassLoader().getResourceAsStream("configurations/commands.yml"), java.nio.charset.StandardCharsets.UTF_8))); + commandsConfiguration.save(commandFile); + // CraftBukkit end - LOGGER.info("Initialized '{}' and '{}'", path1.toAbsolutePath(), path2.toAbsolutePath()); + LOGGER.info("Initialized '{}' and '{}'", settingsFile.toAbsolutePath(), eulaFile.toAbsolutePath()); return; } @@ -79,9 +79,9 @@ return; } -- File file = new File(optionSet.valueOf(optionSpec9)); -- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file); -- String string = Optional.ofNullable(optionSet.valueOf(optionSpec10)).orElse(dedicatedServerSettings.getProperties().levelName); +- File universePath = new File(options.valueOf(universe)); +- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), universePath); +- String levelName = Optional.ofNullable(options.valueOf(worldName)).orElse(settings.getProperties().levelName); + // Paper start - Detect headless JRE + String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck(); + if (awtException != null) { @@ -97,38 +97,38 @@ + org.spigotmc.SpigotConfig.disabledAdvancements = spigotConfiguration.getStringList("advancements.disabled"); // Paper - fix SPIGOT-5885, must be set early in init + + // Paper start - fix SPIGOT-5824 -+ File file; ++ File universePath; + File userCacheFile = new File(Services.USERID_CACHE_FILE); -+ if (optionSet.has("universe")) { -+ file = (File) optionSet.valueOf("universe"); // CraftBukkit -+ userCacheFile = new File(file, Services.USERID_CACHE_FILE); ++ if (options.has("universe")) { ++ universePath = (File) options.valueOf("universe"); // CraftBukkit ++ userCacheFile = new File(universePath, Services.USERID_CACHE_FILE); + } else { -+ file = new File(bukkitConfiguration.getString("settings.world-container", ".")); ++ universePath = new File(bukkitConfiguration.getString("settings.world-container", ".")); + } + // Paper end - fix SPIGOT-5824 -+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionSet); // Paper - pass OptionSet to load paper config files; override authentication service; fix world-container ++ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), universePath, userCacheFile, options); // Paper - pass OptionSet to load paper config files; override authentication service; fix world-container + // CraftBukkit start -+ String string = Optional.ofNullable((String) optionSet.valueOf("world")).orElse(dedicatedServerSettings.getProperties().levelName); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(file.toPath()); -- LevelStorageSource.LevelStorageAccess levelStorageAccess = levelStorageSource.validateAndCreateAccess(string); -+ LevelStorageSource.LevelStorageAccess levelStorageAccess = levelStorageSource.validateAndCreateAccess(string, LevelStem.OVERWORLD); ++ String levelName = Optional.ofNullable((String) options.valueOf("world")).orElse(settings.getProperties().levelName); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(universePath.toPath()); +- LevelStorageSource.LevelStorageAccess access = levelStorageSource.validateAndCreateAccess(levelName); ++ LevelStorageSource.LevelStorageAccess access = levelStorageSource.validateAndCreateAccess(levelName, LevelStem.OVERWORLD); + // CraftBukkit end - Dynamic dataTag; - if (levelStorageAccess.hasWorldData()) { - LevelSummary summary; -@@ -166,12 +_,36 @@ + Dynamic levelDataTag; + if (access.hasWorldData()) { + Dynamic levelDataUnfixed; +@@ -150,12 +_,36 @@ + levelDataTag = null; } - Dynamic dynamic = dataTag; -- boolean hasOptionSpec = optionSet.has(optionSpec7); -+ boolean hasOptionSpec = optionSet.has("safeMode"); // CraftBukkit - if (hasOptionSpec) { +- boolean safeModeEnabled = options.has(safeMode); ++ boolean safeModeEnabled = options.has("safeMode"); // CraftBukkit + if (safeModeEnabled) { LOGGER.warn("Safe mode active, only vanilla datapack will be loaded"); } - PackRepository packRepository = ServerPacksSource.createPackRepository(levelStorageAccess); + PackRepository packRepository = ServerPacksSource.createPackRepository(access); + // CraftBukkit start -+ File bukkitDataPackFolder = new File(levelStorageAccess.getLevelPath(net.minecraft.world.level.storage.LevelResource.DATAPACK_DIR).toFile(), "bukkit"); ++ File bukkitDataPackFolder = new File(access.getLevelPath(net.minecraft.world.level.storage.LevelResource.DATAPACK_DIR).toFile(), "bukkit"); + if (!bukkitDataPackFolder.exists()) { + bukkitDataPackFolder.mkdirs(); + } @@ -154,106 +154,107 @@ WorldStem worldStem; try { -@@ -180,6 +_,7 @@ +@@ -164,6 +_,7 @@ executor -> WorldLoader.load( - initConfig, + worldLoadConfig, context -> { + worldLoader.set(context); // CraftBukkit - Registry registry = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM); - if (dynamic != null) { - LevelDataAndDimensions levelDataAndDimensions = LevelStorageSource.getLevelDataAndDimensions( -@@ -191,7 +_,7 @@ + Registry datapackDimensions = context.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM); + if (levelDataTag != null) { + LevelDataAndDimensions worldData = LevelStorageSource.getLevelDataAndDimensions( +@@ -174,7 +_,7 @@ + ); } else { LOGGER.info("No existing world data, creating new world"); - return createNewWorldData( -- dedicatedServerSettings, context, registry, optionSet.has(optionSpec2), optionSet.has(optionSpec3) -+ dedicatedServerSettings, context, registry, optionSet.has("demo"), optionSet.has("bonusChest") // CraftBukkit - ); +- return createNewWorldData(settings, context, datapackDimensions, options.has(demo), options.has(bonusChest)); ++ return createNewWorldData(settings, context, datapackDimensions, options.has("demo"), options.has("bonusChest")); // CraftBukkit } }, -@@ -209,6 +_,7 @@ + WorldStem::new, +@@ -191,6 +_,7 @@ return; } + /* - RegistryAccess.Frozen frozen = worldStem.registries().compositeAccess(); - WorldData worldData = worldStem.worldData(); - boolean hasOptionSpec1 = optionSet.has(optionSpec6); -@@ -217,22 +_,50 @@ + RegistryAccess.Frozen registryHolder = worldStem.registries().compositeAccess(); + WorldData data = worldStem.worldDataAndGenSettings().data(); + boolean recreateRegionFilesValue = options.has(recreateRegionFiles); +@@ -199,22 +_,51 @@ } - levelStorageAccess.saveDataTag(frozen, worldData); + access.saveDataTag(data); + */ final DedicatedServer dedicatedServer = MinecraftServer.spin( - thread1 -> { - DedicatedServer dedicatedServer1 = new DedicatedServer( -- thread1, levelStorageAccess, packRepository, worldStem, dedicatedServerSettings, DataFixers.getDataFixer(), services + thread -> { + DedicatedServer server = new DedicatedServer( +- thread, access, packRepository, worldStem, Optional.empty(), settings, DataFixers.getDataFixer(), services + // CraftBukkit start -+ optionSet, ++ options, + worldLoader.get(), -+ thread1, -+ levelStorageAccess, ++ thread, ++ access, + packRepository, + worldStem, -+ dedicatedServerSettings, ++ Optional.empty(), ++ settings, + DataFixers.getDataFixer(), + services ); + /* - dedicatedServer1.setPort(optionSet.valueOf(optionSpec11)); -- dedicatedServer1.setDemo(optionSet.has(optionSpec2)); + server.setPort(options.valueOf(port)); +- server.setDemo(options.has(demo)); + */ + // Paper start -+ if (optionSet.has("serverId")) { -+ dedicatedServer1.setId((String) optionSet.valueOf("serverId")); ++ if (options.has("serverId")) { ++ server.setId((String) options.valueOf("serverId")); + } -+ dedicatedServer1.setDemo(optionSet.has("demo")); ++ server.setDemo(options.has("demo")); + // Paper end + /* - dedicatedServer1.setId(optionSet.valueOf(optionSpec12)); -- boolean flag = !optionSet.has(optionSpec) && !optionSet.valuesOf(optionSpec15).contains("nogui"); + server.setId(options.valueOf(serverId)); +- boolean gui = !options.has(nogui) && !options.valuesOf(nonOptions).contains("nogui"); + */ -+ boolean flag = !optionSet.has("nogui") && !optionSet.nonOptionArguments().contains("nogui"); - if (flag && !GraphicsEnvironment.isHeadless()) { - dedicatedServer1.showGui(); ++ boolean gui = !options.has("nogui") && !options.nonOptionArguments().contains("nogui"); + if (gui && !GraphicsEnvironment.isHeadless()) { + server.showGui(); } + // Paper start -+ if (optionSet.has("port")) { -+ int port = (Integer) optionSet.valueOf("port"); ++ if (options.has("port")) { ++ int port = (Integer) options.valueOf("port"); + if (port > 0) { -+ dedicatedServer1.setPort(port); ++ server.setPort(port); + } + } + // Paper end - return dedicatedServer1; + return server; } ); + /* CraftBukkit start - Thread thread = new Thread("Server Shutdown Thread") { + Thread shutdownThread = new Thread("Server Shutdown Thread") { @Override public void run() { -@@ -241,12 +_,13 @@ +@@ -223,12 +_,13 @@ }; - thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); - Runtime.getRuntime().addShutdownHook(thread); + shutdownThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); + Runtime.getRuntime().addShutdownHook(shutdownThread); + */ // CraftBukkit end - } catch (Throwable var42) { - LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", var42); + } catch (Throwable var40) { + LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", var40); } } -- private static WorldLoader.DataLoadOutput createNewWorldData( -+ public static WorldLoader.DataLoadOutput createNewWorldData( // Paper - public - DedicatedServerSettings settings, WorldLoader.DataLoadContext context, Registry stemRegistry, boolean demo, boolean generateBonusChest - ) { - LevelSettings levelSettings; -@@ -314,7 +_,7 @@ - RegistryAccess registryAccess, - boolean recreateRegionFiles +- private static WorldLoader.DataLoadOutput createNewWorldData( ++ public static WorldLoader.DataLoadOutput createNewWorldData( // Paper - public + final DedicatedServerSettings settings, + final WorldLoader.DataLoadContext context, + final Registry datapackDimensions, +@@ -299,7 +_,7 @@ + final RegistryAccess registryAccess, + final boolean recreateRegionFiles ) { - LOGGER.info("Forcing world upgrade!"); -+ LOGGER.info("Forcing world upgrade! {}", levelStorage.getLevelId()); // CraftBukkit ++ LOGGER.info("Forcing world upgrade! {}", storageSource.getLevelId()); // CraftBukkit - try (WorldUpgrader worldUpgrader = new WorldUpgrader(levelStorage, dataFixer, worldData, registryAccess, eraseCache, recreateRegionFiles)) { - Component component = null; + try (WorldUpgrader upgrader = new WorldUpgrader(storageSource, fixerUpper, registryAccess, eraseCache, recreateRegionFiles)) { + Component lastStatus = null; diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index b0c73c66dc97..bf7eec7664a6 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -186,11 +_,13 @@ +@@ -192,11 +_,13 @@ import org.slf4j.Logger; - public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, CommandSource, ChunkIOErrorReporter { + public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements CommandSource, ServerInfo, ChunkIOErrorReporter { + private static MinecraftServer SERVER; // Paper public static final Logger LOGGER = LogUtils.getLogger(); + public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper @@ -15,7 +15,16 @@ private static final int OVERLOADED_TICKS_THRESHOLD = 20; private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; -@@ -217,7 +_,7 @@ +@@ -219,7 +_,7 @@ + public final PlayerDataStorage playerDataStorage; + private final SavedDataStorage savedDataStorage; + private final List tickables = Lists.newArrayList(); +- private final GameRules gameRules; ++ // Paper - per-level GameRules + private MetricsRecorder metricsRecorder = InactiveMetricsRecorder.INSTANCE; + private Consumer onMetricsRecordingStopped = results -> this.stopRecordingMetrics(); + private Consumer onMetricsRecordingFinished = ignored -> {}; +@@ -227,7 +_,7 @@ private MinecraftServer.@Nullable TimeProfiler debugCommandProfiler; private boolean debugCommandProfilerDelayStart; private ServerConnectionListener connection; @@ -24,7 +33,7 @@ private @Nullable ServerStatus status; private ServerStatus.@Nullable Favicon statusIcon; private final RandomSource random = RandomSource.create(); -@@ -228,13 +_,14 @@ +@@ -238,13 +_,14 @@ private Map, ServerLevel> levels = Maps.newLinkedHashMap(); private PlayerList playerList; private volatile boolean running = true; @@ -40,9 +49,35 @@ private int playerIdleTimeout; private final long[] tickTimesNanos = new long[100]; private long aggregatedTickTimesNanos = 0L; -@@ -281,10 +_,109 @@ +@@ -272,7 +_,7 @@ + private @Nullable CommandStorage commandStorage; + private final CustomBossEvents customBossEvents; + private final RandomSequences randomSequences; +- private final WeatherData weatherData; ++ // Paper - per-level WeatherData + private final ServerFunctionManager functionManager; + private boolean enforceWhitelist; + private boolean usingWhitelist; +@@ -292,13 +_,14 @@ + private final SuppressedExceptionCollector suppressedExceptions = new SuppressedExceptionCollector(); private final DiscontinuousFrame tickFrame; private final PacketProcessor packetProcessor; +- private final TimerQueue scheduledEvents; ++ // Paper - per-level scheduledEvents + private final ServerClockManager clockManager; + + public static S spin(final Function factory) { + AtomicReference serverReference = new AtomicReference<>(); +- Thread thread = new Thread(() -> serverReference.get().runServer(), "Server thread"); ++ Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> serverReference.get().runServer(), "Server thread"); + thread.setUncaughtExceptionHandler((t, e) -> LOGGER.error("Uncaught exception in server thread", e)); ++ thread.setPriority(Thread.NORM_PRIORITY + 2); // Paper - Perf: Boost priority + if (Runtime.getRuntime().availableProcessors() > 4) { + thread.setPriority(8); + } +@@ -309,7 +_,124 @@ + return server; + } + // CraftBukkit start + public final WorldLoader.DataLoadContext worldLoaderContext; @@ -81,6 +116,21 @@ + private long currentTickStart; + private long scheduledTickStart; + private long taskExecutionTime; ++ /** ++ * The tickCount field is not incremented exactly where and when we want for our ++ * usage here. ++ *

    ++ * There are two problems we need to fix: ++ *
      ++ *
    1. The tickCount field is not incremented when paused through integrated server.
    2. ++ *
    3. The tickCount field is incremented after draining tasks (during server tick).
    4. ++ *
    ++ * Our goal with the tick count here is to prevent executing tasks scheduled after the start ++ * of the current tick, which is marked by the task draining. ++ * ++ * @see #runAllTasksAtTickStart ++ */ ++ private final java.util.concurrent.atomic.AtomicInteger tickTaskTickCount = new java.util.concurrent.atomic.AtomicInteger(); + private final Object statsLock = new Object(); + private @Nullable double[] tps; + private ca.spottedleaf.moonrise.common.time.TickData.@Nullable MSPTData msptData5s; @@ -142,37 +192,29 @@ + } + // Paper end - improve tick loop + - public static S spin(Function threadFunction) { - AtomicReference atomicReference = new AtomicReference<>(); -- Thread thread = new Thread(() -> atomicReference.get().runServer(), "Server thread"); -+ Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> atomicReference.get().runServer(), "Server thread"); - thread.setUncaughtExceptionHandler((thread1, exception) -> LOGGER.error("Uncaught exception in server thread", exception)); -+ thread.setPriority(Thread.NORM_PRIORITY+2); // Paper - Perf: Boost priority - if (Runtime.getRuntime().availableProcessors() > 4) { - thread.setPriority(8); - } -@@ -296,6 +_,10 @@ - } - public MinecraftServer( + // CraftBukkit start + joptsimple.OptionSet options, + WorldLoader.DataLoadContext worldLoaderContext, + // CraftBukkit end - Thread serverThread, - LevelStorageSource.LevelStorageAccess storageSource, - PackRepository packRepository, -@@ -306,18 +_,19 @@ - LevelLoadListener levelLoadListener + final Thread serverThread, + final LevelStorageSource.LevelStorageAccess storageSource, + final PackRepository packRepository, +@@ -322,27 +_,27 @@ + final boolean propagatesCrashes ) { - super("Server"); + super("Server", propagatesCrashes); + SERVER = this; // Paper - better singleton this.registries = worldStem.registries(); - this.worldData = worldStem.worldData(); - if (!this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { + if (false && !this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { // CraftBukkit - initialised later throw new IllegalStateException("Missing Overworld dimension data"); } else { + this.savedDataStorage = new SavedDataStorage(storageSource.getLevelPath(LevelResource.DATA), fixerUpper, this.registries.compositeAccess()); + this.worldData = worldStem.worldDataAndGenSettings().data(); + this.worldGenSettings = worldStem.worldDataAndGenSettings().genSettings(); +- this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); ++ // this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); // Paper - save in level storage this.proxy = proxy; this.packRepository = packRepository; this.resources = new MinecraftServer.ReloadableResources(worldStem.resourceManager(), worldStem.dataPackResources()); @@ -181,14 +223,26 @@ + // this.connection = new ServerConnectionListener(this); // Spigot this.tickRateManager = new ServerTickRateManager(this); - this.levelLoadListener = levelLoadListener; -+ // Paper - per level load listener - move LevelLoadListener to ServerLevel ++ // Paper - per-level load listener - move LevelLoadListener to ServerLevel this.storageSource = storageSource; this.playerDataStorage = storageSource.createPlayerStorage(); + this.randomSequences = this.savedDataStorage.computeIfAbsent(RandomSequences.TYPE); +- this.weatherData = this.getDataStorage().computeIfAbsent(WeatherData.TYPE); +- this.gameRules = new GameRules(this.worldData.enabledFeatures(), this.savedDataStorage.computeIfAbsent(GameRuleMap.TYPE)); +- gameRules.ifPresent(g -> this.gameRules.setAll(g, null)); ++ // Paper - per-level WeatherData ++ // Paper - per-level GameRules this.fixerUpper = fixerUpper; -@@ -337,6 +_,38 @@ - this.serverActivityMonitor = new ServerActivityMonitor(this.notificationManager, 30); - this.packetProcessor = new PacketProcessor(serverThread); - } + this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); + HolderGetter blockLookup = this.registries +@@ -362,8 +_,40 @@ + this.clockManager = this.getDataStorage().computeIfAbsent(ServerClockManager.TYPE); + this.clockManager.init(this); + this.customBossEvents = this.savedDataStorage.computeIfAbsent(CustomBossEvents.TYPE); +- this.scheduledEvents = this.savedDataStorage.computeIfAbsent(TimerQueue.TYPE); +- } ++ // Paper - per-level scheduledEvents ++ } + // CraftBukkit start + this.options = options; + this.worldLoaderContext = worldLoaderContext; @@ -224,13 +278,13 @@ } protected abstract boolean initServer() throws IOException; -@@ -369,15 +_,15 @@ +@@ -400,15 +_,15 @@ }; } - protected void loadLevel() { -+ protected void loadLevel(String levelId) { // CraftBukkit - boolean flag = !JvmProfiler.INSTANCE.isRunning() ++ protected void loadLevel(final String levelId) { // CraftBukkit + boolean startedWorldLoadProfiling = !JvmProfiler.INSTANCE.isRunning() && SharedConstants.DEBUG_JFR_PROFILING_ENABLE_LEVEL_LOADING && JvmProfiler.INSTANCE.start(Environment.from(this)); ProfiledDuration profiledDuration = JvmProfiler.INSTANCE.onWorldLoadedStarted(); @@ -245,7 +299,7 @@ if (profiledDuration != null) { profiledDuration.finish(true); } -@@ -391,31 +_,127 @@ +@@ -422,33 +_,134 @@ } } @@ -267,7 +321,6 @@ + this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD); + this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark + this.server.spark.enableAfterPlugins(this.server); // Paper - spark -+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins + io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // Paper - reset invalid state for event fire below + io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - call commands event for regular plugins + this.server.getCommandMap().registerServerAliases(); // Paper - relocate initial CommandMap#registerServerAliases() call @@ -281,70 +334,74 @@ } - protected void createLevels() { -- ServerLevelData serverLevelData = this.worldData.overworldData(); -- boolean isDebugWorld = this.worldData.isDebugWorld(); -- Registry registry = this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM); -- WorldOptions worldOptions = this.worldData.worldGenOptions(); +- ServerLevelData levelData = this.worldData.overworldData(); +- boolean isDebug = this.worldData.isDebugWorld(); +- Registry dimensions = this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM); +- WorldOptions worldOptions = this.worldGenSettings.options(); + // Paper start - rework world loading process + public void createLevel( + LevelStem levelStem, + io.papermc.paper.world.PaperWorldLoader.WorldLoadingInfo loadingInfo, + LevelStorageSource.LevelStorageAccess levelStorageAccess, -+ net.minecraft.world.level.storage.PrimaryLevelData serverLevelData ++ net.minecraft.world.level.storage.LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings + ) { -+ WorldOptions worldOptions = serverLevelData.worldGenOptions(); ++ final WorldOptions worldOptions = worldDataAndGenSettings.genSettings().options(); ++ final ResourceKey dimensionKey = ResourceKey.create(Registries.DIMENSION, loadingInfo.stemKey().identifier()); ++ final SavedDataStorage savedDataStorage = new SavedDataStorage(levelStorageAccess.getLevelPath(LevelResource.DATA), this.getFixerUpper(), this.registryAccess()); ++ savedDataStorage.set(WorldGenSettings.TYPE, worldDataAndGenSettings.genSettings()); long seed = worldOptions.seed(); - long l = BiomeManager.obfuscateSeed(seed); - List list = ImmutableList.of( - new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(serverLevelData) - ); -- LevelStem levelStem = registry.getValue(LevelStem.OVERWORLD); -- ServerLevel serverLevel = new ServerLevel( -- this, this.executor, this.storageSource, serverLevelData, Level.OVERWORLD, levelStem, isDebugWorld, l, list, true, null + long biomeZoomSeed = BiomeManager.obfuscateSeed(seed); + List overworldCustomSpawners = ImmutableList.of( +- new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(this.savedDataStorage) +- ); +- LevelStem overworldData = dimensions.getValue(LevelStem.OVERWORLD); +- ServerLevel overworld = new ServerLevel( +- this, this.executor, this.storageSource, levelData, Level.OVERWORLD, overworldData, isDebug, biomeZoomSeed, overworldCustomSpawners, true +- ); +- this.levels.put(Level.OVERWORLD, overworld); ++ new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(savedDataStorage) // Paper - save to world data ++ ); + final org.bukkit.generator.ChunkGenerator chunkGenerator = this.server.getGenerator(loadingInfo.name()); + org.bukkit.generator.BiomeProvider biomeProvider = this.server.getBiomeProvider(loadingInfo.name()); + final org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo( -+ serverLevelData, ++ worldDataAndGenSettings, + levelStorageAccess, + org.bukkit.World.Environment.getEnvironment(loadingInfo.dimension()), + levelStem.type().value(), + levelStem.generator(), + this.registryAccess() - ); -- this.levels.put(Level.OVERWORLD, serverLevel); ++ ); + if (biomeProvider == null && chunkGenerator != null) { + biomeProvider = chunkGenerator.getDefaultBiomeProvider(worldInfo); + } -+ final ResourceKey dimensionKey = ResourceKey.create(Registries.DIMENSION, loadingInfo.stemKey().identifier()); + ServerLevel serverLevel; + if (loadingInfo.stemKey() == LevelStem.OVERWORLD) { + serverLevel = new ServerLevel( + this, + this.executor, + levelStorageAccess, -+ serverLevelData, ++ worldDataAndGenSettings, + dimensionKey, + levelStem, -+ serverLevelData.isDebugWorld(), -+ l, -+ list, ++ worldDataAndGenSettings.data().isDebugWorld(), ++ biomeZoomSeed, ++ overworldCustomSpawners, + true, -+ null, + org.bukkit.World.Environment.getEnvironment(loadingInfo.dimension()), + chunkGenerator, -+ biomeProvider ++ biomeProvider, ++ savedDataStorage + ); -+ this.worldData = serverLevelData; ++ this.worldData = worldDataAndGenSettings.data(); + this.worldData.setGameType(((net.minecraft.server.dedicated.DedicatedServer) this).getProperties().gameMode.get()); // From DedicatedServer.init - DimensionDataStorage dataStorage = serverLevel.getDataStorage(); - this.scoreboard.load(dataStorage.computeIfAbsent(ScoreboardSaveData.TYPE).getData()); - this.commandStorage = new CommandStorage(dataStorage); - this.stopwatches = dataStorage.computeIfAbsent(Stopwatches.TYPE); + this.scoreboard.load(this.savedDataStorage.computeIfAbsent(ScoreboardSaveData.TYPE).getData()); + this.commandStorage = new CommandStorage(this.savedDataStorage); + this.stopwatches = this.savedDataStorage.computeIfAbsent(Stopwatches.TYPE); + this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, serverLevel.getScoreboard()); + } else { + final List spawners; + if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && levelStem.type().is(net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD)) { -+ spawners = list; ++ spawners = overworldCustomSpawners; + } else { + spawners = Collections.emptyList(); + } @@ -352,108 +409,73 @@ + this, + this.executor, + levelStorageAccess, -+ serverLevelData, ++ worldDataAndGenSettings, + dimensionKey, + levelStem, + this.worldData.isDebugWorld(), -+ l, ++ biomeZoomSeed, + spawners, + true, -+ this.overworld().getRandomSequences(), + org.bukkit.World.Environment.getEnvironment(loadingInfo.dimension()), + chunkGenerator, -+ biomeProvider ++ biomeProvider, ++ savedDataStorage + ); + } + this.addLevel(serverLevel); -+ this.initWorld(serverLevel, serverLevelData, worldOptions); ++ this.initWorld(serverLevel); + } -+ public void initWorld(ServerLevel serverLevel, net.minecraft.world.level.storage.PrimaryLevelData serverLevelData, WorldOptions worldOptions) { -+ final boolean isDebugWorld = this.worldData.isDebugWorld(); -+ if (serverLevel.generator != null) { -+ serverLevel.getWorld().getPopulators().addAll(serverLevel.generator.getDefaultPopulators(serverLevel.getWorld())); ++ public void initWorld(ServerLevel overworld) { ++ final net.minecraft.world.level.storage.PrimaryLevelData levelData = overworld.serverLevelData; ++ final WorldOptions worldOptions = overworld.worldDataAndGenSettings.genSettings().options(); ++ final boolean isDebug = this.worldData.isDebugWorld(); ++ if (overworld.generator != null) { ++ overworld.getWorld().getPopulators().addAll(overworld.generator.getDefaultPopulators(overworld.getWorld())); + } -+ this.initWorldBorder(serverLevelData, serverLevel); -+ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(serverLevel.getWorld())); ++ overworld.getWorldBorder().world = overworld; ++ overworld.getWorldBorder().setAbsoluteMaxSize(this.getAbsoluteMaxWorldSize()); ++ this.getPlayerList().addWorldborderListener(overworld); ++ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(overworld.getWorld())); + // Paper end - rework world loading process - if (!serverLevelData.isInitialized()) { + if (!levelData.isInitialized()) { try { -- setInitialSpawn(serverLevel, serverLevelData, worldOptions.generateBonusChest(), isDebugWorld, this.levelLoadListener); -+ setInitialSpawn(serverLevel, serverLevelData, worldOptions.generateBonusChest(), isDebugWorld, serverLevel.levelLoadListener); // Paper - per world level load listener - serverLevelData.setInitialized(true); - if (isDebugWorld) { - this.setupDebugLevel(this.worldData); -@@ -435,38 +_,16 @@ - } - - GlobalPos globalPos = this.selectLevelLoadFocusPos(); -- this.levelLoadListener.updateFocus(globalPos.dimension(), new ChunkPos(globalPos.pos())); -- if (this.worldData.getCustomBossEvents() != null) { -- this.getCustomBossEvents().load(this.worldData.getCustomBossEvents(), this.registryAccess()); -+ serverLevel.levelLoadListener.updateFocus(globalPos.dimension(), new ChunkPos(globalPos.pos())); // Paper - per world load listener -+ if (serverLevelData.getCustomBossEvents() != null) { // Paper - rework world loading process -+ this.getCustomBossEvents().load(serverLevelData.getCustomBossEvents(), this.registryAccess()); // Paper - rework world loading process +- setInitialSpawn(overworld, levelData, worldOptions.generateBonusChest(), isDebug, this.levelLoadListener); ++ setInitialSpawn(overworld, levelData, worldOptions.generateBonusChest(), isDebug, overworld.levelLoadListener); // Paper - per world level load listener + levelData.setInitialized(true); + if (isDebug) { +- this.setupDebugLevel(this.worldData); ++ this.setupDebugLevel(this.worldData, overworld); // Paper - per-level GameRules + } + } catch (Throwable var20) { + CrashReport report = CrashReport.forThrowable(var20, "Exception initializing level"); +@@ -465,25 +_,7 @@ } -- RandomSequences randomSequences = serverLevel.getRandomSequences(); -- boolean flag = false; + GlobalPos focusPos = this.selectLevelLoadFocusPos(); +- this.levelLoadListener.updateFocus(focusPos.dimension(), ChunkPos.containing(focusPos.pos())); - -- for (Entry, LevelStem> entry : registry.entrySet()) { -- ResourceKey resourceKey = entry.getKey(); -- ServerLevel serverLevel1; -- if (resourceKey != LevelStem.OVERWORLD) { -- ResourceKey resourceKey1 = ResourceKey.create(Registries.DIMENSION, resourceKey.identifier()); -- DerivedLevelData derivedLevelData = new DerivedLevelData(this.worldData, serverLevelData); -- serverLevel1 = new ServerLevel( -- this, -- this.executor, -- this.storageSource, -- derivedLevelData, -- resourceKey1, -- entry.getValue(), -- isDebugWorld, -- l, -- ImmutableList.of(), -- false, -- randomSequences +- for (Entry, LevelStem> entry : dimensions.entrySet()) { +- ResourceKey name = entry.getKey(); +- ServerLevel level; +- if (name != LevelStem.OVERWORLD) { +- ResourceKey dimension = ResourceKey.create(Registries.DIMENSION, name.identifier()); +- DerivedLevelData derivedLevelData = new DerivedLevelData(this.worldData, levelData); +- level = new ServerLevel( +- this, this.executor, this.storageSource, derivedLevelData, dimension, entry.getValue(), isDebug, biomeZoomSeed, ImmutableList.of(), false - ); -- this.levels.put(resourceKey1, serverLevel1); +- this.levels.put(dimension, level); - } else { -- serverLevel1 = serverLevel; +- level = overworld; - } - -+ // Paper start - rework world loading process -+ } -+ private void initWorldBorder(net.minecraft.world.level.storage.PrimaryLevelData serverLevelData, ServerLevel serverLevel) { -+ final ServerLevel serverLevel1 = serverLevel; // Rename for below code -+ // Paper end - rework world loading process - Optional legacyWorldBorderSettings = serverLevelData.getLegacyWorldBorderSettings(); - if (legacyWorldBorderSettings.isPresent()) { - WorldBorder.Settings settings = legacyWorldBorderSettings.get(); -@@ -489,16 +_,14 @@ - dataStorage1.set(WorldBorder.TYPE, worldBorder); - } - -- flag = true; -+ serverLevelData.setLegacyWorldBorderSettings(Optional.empty()); // Paper - rework world loading process - } - -- serverLevel1.getWorldBorder().setAbsoluteMaxSize(this.getAbsoluteMaxWorldSize()); -- this.getPlayerList().addWorldborderListener(serverLevel1); +- level.getWorldBorder().setAbsoluteMaxSize(this.getAbsoluteMaxWorldSize()); +- this.getPlayerList().addWorldborderListener(level); - } -- -- if (flag) { -- serverLevelData.setLegacyWorldBorderSettings(Optional.empty()); -- } -+ // Paper start - rework world loading process -+ serverLevel.getWorldBorder().world = serverLevel; -+ serverLevel.getWorldBorder().setAbsoluteMaxSize(this.getAbsoluteMaxWorldSize()); -+ this.getPlayerList().addWorldborderListener(serverLevel); -+ // Paper end - rework world loading process ++ overworld.levelLoadListener.updateFocus(focusPos.dimension(), ChunkPos.containing(focusPos.pos())); // Paper - per world load listener } private static void setInitialSpawn( -@@ -510,6 +_,28 @@ +@@ -499,6 +_,28 @@ levelData.setSpawn(LevelData.RespawnData.of(level.dimension(), BlockPos.ZERO.above(80), 0.0F, 0.0F)); } else { ServerChunkCache chunkSource = level.getChunkSource(); @@ -479,74 +501,83 @@ + } + } + // CraftBukkit end - ChunkPos chunkPos = new ChunkPos(chunkSource.randomState().sampler().findSpawnPosition()); + ChunkPos spawnChunk = ChunkPos.containing(chunkSource.randomState().sampler().findSpawnPosition()); levelLoadListener.start(LevelLoadListener.Stage.PREPARE_GLOBAL_SPAWN, 0); - levelLoadListener.updateFocus(level.dimension(), chunkPos); -@@ -566,10 +_,13 @@ - serverLevelData.setGameType(GameType.SPECTATOR); + levelLoadListener.updateFocus(level.dimension(), spawnChunk); +@@ -544,19 +_,22 @@ + } + } + +- private void setupDebugLevel(final WorldData worldData) { ++ private void setupDebugLevel(final WorldData worldData, final ServerLevel level) { // Paper - pass level + worldData.setDifficulty(Difficulty.PEACEFUL); + worldData.setDifficultyLocked(true); + ServerLevelData levelData = worldData.overworldData(); +- this.getGameRules().set(GameRules.ADVANCE_WEATHER, false, this); ++ level.getGameRules().set(GameRules.ADVANCE_WEATHER, false, level); // Paper - per-level GameRules + this.clockManager.moveToTimeMarker(this.registryAccess().getOrThrow(WorldClocks.OVERWORLD), ClockTimeMarkers.NOON); + levelData.setGameType(GameType.SPECTATOR); } - private void prepareLevels() { + // CraftBukkit start -+ public void prepareLevel(ServerLevel serverLevel) { ++ public void prepareLevel(ServerLevel level) { + this.forceTicks = true; + // CraftBukkit end ChunkLoadCounter chunkLoadCounter = new ChunkLoadCounter(); -- for (ServerLevel serverLevel : this.levels.values()) { +- for (ServerLevel level : this.levels.values()) { + if (true) { // CraftBukkit - chunkLoadCounter.track(serverLevel, () -> { - TicketStorage ticketStorage = serverLevel.getDataStorage().get(TicketStorage.TYPE); - if (ticketStorage != null) { -@@ -578,17 +_,19 @@ + chunkLoadCounter.track(level, () -> { + TicketStorage savedTickets = level.getDataStorage().get(TicketStorage.TYPE); + if (savedTickets != null) { +@@ -565,17 +_,19 @@ }); } - this.levelLoadListener.start(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.totalChunks()); -+ serverLevel.levelLoadListener.start(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.totalChunks()); // Paper - per world load listener ++ level.levelLoadListener.start(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.totalChunks()); // Paper - per world load listener do { - this.levelLoadListener.update(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.readyChunks(), chunkLoadCounter.totalChunks()); - this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; - this.waitUntilNextTick(); -+ serverLevel.levelLoadListener.update(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.readyChunks(), chunkLoadCounter.totalChunks()); // Paper - per world load listener ++ level.levelLoadListener.update(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS, chunkLoadCounter.readyChunks(), chunkLoadCounter.totalChunks()); // Paper - per world load listener + this.executeModerately(); // CraftBukkit } while (chunkLoadCounter.pendingChunks() > 0); - this.levelLoadListener.finish(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS); - this.updateMobSpawningFlags(); -+ serverLevel.levelLoadListener.finish(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS); // Paper - per world load listener -+ serverLevel.setSpawnSettings(serverLevel.isSpawningMonsters()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean)) ++ level.levelLoadListener.finish(LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS); // Paper - per world load listener ++ level.setSpawnSettings(level.isSpawningMonsters()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean)) this.updateEffectiveRespawnData(); + this.forceTicks = false; // CraftBukkit -+ serverLevel.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API -+ new org.bukkit.event.world.WorldLoadEvent(serverLevel.getWorld()).callEvent(); // Paper - call WorldLoadEvent ++ level.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API ++ new org.bukkit.event.world.WorldLoadEvent(level.getWorld()).callEvent(); // Paper - call WorldLoadEvent } protected GlobalPos selectLevelLoadFocusPos() { -@@ -610,7 +_,7 @@ +@@ -597,7 +_,7 @@ public abstract boolean shouldRconBroadcast(); - public boolean saveAllChunks(boolean suppressLogs, boolean flush, boolean force) { -- this.scoreboard.storeToSaveDataIfDirty(this.overworld().getDataStorage().computeIfAbsent(ScoreboardSaveData.TYPE)); + public boolean saveAllChunks(final boolean silent, final boolean flush, final boolean force) { +- this.scoreboard.storeToSaveDataIfDirty(this.getDataStorage().computeIfAbsent(ScoreboardSaveData.TYPE)); + if (this.overworld() != null) this.scoreboard.storeToSaveDataIfDirty(this.overworld().getDataStorage().computeIfAbsent(ScoreboardSaveData.TYPE)); // Paper - don't try to save if the overworld was not loaded, generally during early startup failures - boolean flag = false; + boolean result = false; - for (ServerLevel serverLevel : this.getAllLevels()) { -@@ -622,8 +_,10 @@ - flag = true; + for (ServerLevel level : this.getAllLevels()) { +@@ -609,8 +_,8 @@ + result = true; } -- this.worldData.setCustomBossEvents(this.getCustomBossEvents().save(this.registryAccess())); -- this.storageSource.saveDataTag(this.registryAccess(), this.worldData, this.getPlayerList().getSingleplayerData()); -+ // CraftBukkit start - moved to ServerLevel#save -+ // this.worldData.setCustomBossEvents(this.getCustomBossEvents().save(this.registryAccess())); -+ // this.storageSource.saveDataTag(this.registryAccess(), this.worldData, this.getPlayerList().getSingleplayerData()); -+ // CraftBukkit end +- GameProfile singleplayerProfile = this.getSingleplayerProfile(); +- this.storageSource.saveDataTag(this.worldData, singleplayerProfile == null ? null : singleplayerProfile.id()); ++ // GameProfile singleplayerProfile = this.getSingleplayerProfile(); // Paper - moved to ServerLevel#save ++ // this.storageSource.saveDataTag(this.worldData, singleplayerProfile == null ? null : singleplayerProfile.id()); // Paper - moved to ServerLevel#save if (flush) { - for (ServerLevel serverLevel : this.getAllLevels()) { - LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", serverLevel.getChunkSource().chunkMap.getStorageName()); -@@ -653,19 +_,49 @@ + this.savedDataStorage.saveAndJoin(); + } else { +@@ -649,19 +_,49 @@ this.stopServer(); } @@ -561,14 +592,15 @@ + } + // CraftBukkit end + - public void stopServer() { + protected void stopServer() { ++ if (Thread.currentThread() == this.serverThread) this.executeAllRecentInternalTasks(); // Paper - execute tasks on stop + // CraftBukkit start - prevent double stopping on multiple threads -+ synchronized(this.stopLock) { ++ synchronized (this.stopLock) { + if (this.hasStopped) return; + this.hasStopped = true; + } -+ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging -+ shutdownThread = Thread.currentThread(); // Paper - Improved watchdog support ++ if (!this.hasLoggedStop && this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging ++ this.shutdownThread = Thread.currentThread(); // Paper - Improved watchdog support + org.spigotmc.WatchdogThread.doStop(); // Paper - Improved watchdog support + // CraftBukkit end this.packetProcessor.close(); @@ -585,7 +617,6 @@ + this.server.waitForAsyncTasksShutdown(); // Paper - Wait for Async Tasks during shutdown + } + // CraftBukkit end -+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.shutdown(); // Paper - Plugin remapping this.getConnection().stop(); this.isSaving = true; if (this.playerList != null) { @@ -597,7 +628,7 @@ } LOGGER.info("Saving worlds"); -@@ -707,6 +_,20 @@ +@@ -704,6 +_,20 @@ } catch (IOException var4) { LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), var4); } @@ -618,22 +649,22 @@ } public String getLocalIp() { -@@ -722,6 +_,14 @@ +@@ -719,6 +_,14 @@ } - public void halt(boolean waitForShutdown) { + public void halt(final boolean wait) { + // Paper start - allow passing of the intent to restart -+ this.safeShutdown(waitForShutdown, false); ++ this.safeShutdown(wait, false); + } -+ public void safeShutdown(boolean waitForShutdown, boolean isRestarting) { ++ public void safeShutdown(final boolean wait, final boolean isRestarting) { + this.isRestarting = isRestarting; + this.hasLoggedStop = true; // Paper - Debugging -+ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging ++ if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging + // Paper end this.running = false; - if (waitForShutdown) { + if (wait) { try { -@@ -732,6 +_,118 @@ +@@ -729,6 +_,122 @@ } } @@ -684,8 +715,13 @@ + profiler.push("moonrise:run_all_tasks"); + + profiler.push("moonrise:run_all_server"); -+ // avoid calling MinecraftServer#pollTask - we just want to execute queued tasks -+ while (super.pollTask()) { ++ // avoid calling pollTask - we just want to execute queued tasks ++ final int currentTick = this.tickTaskTickCount.incrementAndGet(); ++ final java.util.function.Predicate taskPredicate = (final TickTask task) -> { ++ // only run tasks scheduled before the current tick - which we incremented above ++ return currentTick - task.getTick() > 0; // currentTick > tick accounting for overflow ++ }; ++ while (this.runTaskIf(taskPredicate)) { + // execute small amounts of other tasks just in case the number of tasks we are + // draining is large - chunk system and packet processing may be latency sensitive + @@ -722,7 +758,6 @@ + } + + // execute tasks while there are tasks and there is time left -+ // note: we do not need to bypass the task execution check here (like managedBlock) since it checks time + while (this.pollTask() && (Util.getNanos() - deadline < 0L)); + + final long now = Util.getNanos(); @@ -752,7 +787,7 @@ protected void runServer() { try { if (!this.initServer()) { -@@ -739,26 +_,73 @@ +@@ -736,30 +_,73 @@ } this.nextTickTimeNanos = Util.getNanos(); @@ -791,70 +826,74 @@ + // Paper end - Improve outdated version checking + while (this.running) { -- long l; +- long thisTickNanos; + final long tickStart = System.nanoTime(); // Paper - improve tick loop -+ long l; // Paper - improve tick loop - diff on change, expect this to be tick interval ++ long thisTickNanos; // Paper - improve tick loop - diff on change, expect this to be tick interval if (!this.isPaused() && this.tickRateManager.isSprinting() && this.tickRateManager.checkShouldSprintThisTick()) { - l = 0L; + thisTickNanos = 0L; - this.nextTickTimeNanos = Util.getNanos(); - this.lastOverloadWarningNanos = this.nextTickTimeNanos; -+ this.tickSchedule.setNextPeriod(tickStart, l); // Paper - improve tick loop ++ this.tickSchedule.setNextPeriod(tickStart, thisTickNanos); // Paper - improve tick loop } else { - l = this.tickRateManager.nanosecondsPerTick(); -- long l1 = Util.getNanos() - this.nextTickTimeNanos; -- if (l1 > OVERLOADED_THRESHOLD_NANOS + 20L * l -- && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= OVERLOADED_WARNING_INTERVAL_NANOS + 100L * l) { -- long l2 = l1 / l; -- LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", l1 / TimeUtil.NANOSECONDS_PER_MILLISECOND, l2); -- this.nextTickTimeNanos += l2 * l; + thisTickNanos = this.tickRateManager.nanosecondsPerTick(); +- long behindTimeNanos = Util.getNanos() - this.nextTickTimeNanos; +- if (behindTimeNanos > OVERLOADED_THRESHOLD_NANOS + 20L * thisTickNanos +- && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= OVERLOADED_WARNING_INTERVAL_NANOS + 100L * thisTickNanos) { +- long ticks = behindTimeNanos / thisTickNanos; +- LOGGER.warn( +- "Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", +- behindTimeNanos / TimeUtil.NANOSECONDS_PER_MILLISECOND, +- ticks +- ); +- this.nextTickTimeNanos += ticks * thisTickNanos; - this.lastOverloadWarningNanos = this.nextTickTimeNanos; + // Paper start - improve tick loop + // handle catchup logic -+ final long ticksBehind = Math.max(1L, this.tickSchedule.getPeriodsAhead(l, tickStart)); ++ final long ticksBehind = Math.max(1L, this.tickSchedule.getPeriodsAhead(thisTickNanos, tickStart)); + final long catchup = (long)Math.max( + 1, + 5 //ConfigHolder.getConfig().tickLoop.catchupTicks.getOrDefault(MoonriseConfig.TickLoop.DEFAULT_CATCHUP_TICKS).intValue() + ); + + // adjust ticksBehind so that it is not greater-than catchup -+ if (ticksBehind > catchup) { ++ if (ticksBehind - catchup > 0L) { + final long difference = ticksBehind - catchup; -+ this.tickSchedule.advanceBy(difference, l); ++ this.tickSchedule.advanceBy(difference, thisTickNanos); } + + // start next tick -+ this.tickSchedule.advanceBy(1L, l); ++ this.tickSchedule.advanceBy(1L, thisTickNanos); + // Paper end - improve tick loop } + -+ this.nextTickTimeNanos = this.tickSchedule.getDeadline(l); ++ this.nextTickTimeNanos = this.tickSchedule.getDeadline(thisTickNanos); + this.lastOverloadWarningNanos = this.nextTickTimeNanos; + + this.currentTickStart = tickStart; + ++MinecraftServer.currentTick; + // Paper end - improve tick loop - boolean flag = l == 0L; + boolean sprinting = thisTickNanos == 0L; if (this.debugCommandProfilerDelayStart) { -@@ -766,7 +_,7 @@ +@@ -767,7 +_,7 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } -- this.nextTickTimeNanos += l; +- this.nextTickTimeNanos += thisTickNanos; + // Paper - improve tick loop - done above - try (Profiler.Scope scope = Profiler.use(this.createProfiler())) { - this.processPacketsAndTick(flag); -@@ -775,7 +_,7 @@ + try (Profiler.Scope ignored = Profiler.use(this.createProfiler())) { + this.processPacketsAndTick(sprinting); +@@ -776,7 +_,7 @@ this.mayHaveDelayedTasks = true; - this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + l, this.nextTickTimeNanos); + this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + thisTickNanos, this.nextTickTimeNanos); this.startMeasuringTaskExecutionTime(); - this.waitUntilNextTick(); + this.recordTaskExecutionTimeWhileWaiting(); // Paper - improve tick loop - record task execution here on MSPT this.finishMeasuringTaskExecutionTime(); - if (flag) { + if (sprinting) { this.tickRateManager.endTickWork(); -@@ -809,7 +_,7 @@ +@@ -810,7 +_,7 @@ } catch (Throwable var64) { LOGGER.error("Exception stopping the server", var64); } finally { @@ -863,7 +902,7 @@ } } } -@@ -861,7 +_,14 @@ +@@ -862,7 +_,14 @@ } private boolean haveTime() { @@ -878,8 +917,8 @@ + // CraftBukkit end } - public static boolean throwIfFatalException() { -@@ -887,11 +_,11 @@ + public NotificationManager notificationManager() { +@@ -870,11 +_,11 @@ } protected void waitUntilNextTick() { @@ -893,40 +932,57 @@ } finally { this.waitingForNextTick = false; } -@@ -910,17 +_,23 @@ +@@ -892,18 +_,38 @@ + } @Override - public TickTask wrapRunnable(Runnable runnable) { -+ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog -+ if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) { +- public TickTask wrapRunnable(final Runnable runnable) { +- return new TickTask(this.tickCount, runnable); ++ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog ++ public TickTask wrapRunnable(Runnable runnable) { ++ if (this.hasStopped && Thread.currentThread().equals(this.shutdownThread)) { + runnable.run(); + runnable = () -> {}; + } -+ // Paper end - return new TickTask(this.tickCount, runnable); ++ // Paper end - anything that does try to post to main during watchdog crash, run on watchdog ++ return new TickTask(this.tickTaskTickCount.get(), runnable); // Paper - use different tick field for tick tasks (see #shouldRun) } @Override - protected boolean shouldRun(TickTask runnable) { -- return runnable.getTick() + 3 < this.tickCount || this.haveTime(); -+ return runnable.getTick() + 1 < this.tickCount || this.haveTime(); // Paper - improve tick loop - do not stall queued tasks + protected boolean shouldRun(final TickTask task) { +- return task.getTick() + 3 < this.tickCount || this.haveTime(); ++ // Paper start - improve tick loop - do not stall queued tasks ++ // note: make this overflow safe as well ++ return this.tickTaskTickCount.getPlain() - task.getTick() > 0 || ++ /* ++ * Ensure that we execute any task as long as we are waiting for the next tick. ++ * The Vanilla server will use managedBlock when awaiting the next tick, but ++ * we do not. The Vanilla managedBlock function will bypass task execution ++ * checks, and in order to ensure we execute tasks like Vanilla we need to also ++ * bypass task execution checks. ++ * This fixes {@link #recordTaskExecutionTimeWhileWaiting} not executing tasks ++ * that it should be executing. ++ */ ++ this.waitingForNextTick || ++ this.haveTime(); ++ // Paper end - improve tick loop - do not stall queued tasks } @Override - public boolean pollTask() { -- boolean flag = this.pollTaskInternal(); -+ boolean flag = this.packetProcessor.executeSinglePacket() | this.pollTaskInternal(); // Paper - improve tick loop - process packets while waiting inbetween ticks - this.mayHaveDelayedTasks = flag; - return flag; + protected boolean pollTask() { +- boolean mayHaveMoreTasks = this.pollTaskInternal(); ++ boolean mayHaveMoreTasks = this.packetProcessor.executeSinglePacket() | this.pollTaskInternal(); // Paper - improve tick loop - process packets while waiting inbetween ticks + this.mayHaveDelayedTasks = mayHaveMoreTasks; + return mayHaveMoreTasks; } -@@ -929,15 +_,16 @@ +@@ -912,15 +_,16 @@ if (super.pollTask()) { return true; } else { + boolean ret = false; // Paper - force execution of all worlds, do not just bias the first if (this.tickRateManager.isSprinting() || this.shouldRunAllTasks() || this.haveTime()) { - for (ServerLevel serverLevel : this.getAllLevels()) { - if (serverLevel.getChunkSource().pollTask()) { + for (ServerLevel level : this.getAllLevels()) { + if (level.getChunkSource().pollTask()) { - return true; + ret = true; // Paper - force execution of all worlds, do not just bias the first } @@ -938,15 +994,15 @@ } } -@@ -990,26 +_,44 @@ +@@ -973,26 +_,44 @@ } - public void tickServer(BooleanSupplier hasTimeLeft) { + protected void tickServer(final BooleanSupplier haveTime) { + org.spigotmc.WatchdogThread.tick(); // Spigot - long nanos = Util.getNanos(); - int i = this.pauseWhenEmptySeconds() * 20; + long nano = Util.getNanos(); + int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20; + this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping - if (i > 0) { + if (emptyTickThreshold > 0) { - if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting()) { + if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping this.emptyTicks++; @@ -954,9 +1010,9 @@ this.emptyTicks = 0; } - if (this.emptyTicks >= i) { + if (this.emptyTicks >= emptyTickThreshold) { + this.server.spark.tickStart(); // Paper - spark - if (this.emptyTicks == i) { + if (this.emptyTicks == emptyTickThreshold) { LOGGER.info("Server empty for {} seconds, pausing", this.pauseWhenEmptySeconds()); this.autoSave(); } @@ -983,8 +1039,8 @@ + new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events this.tickCount++; this.tickRateManager.tick(); - this.tickChildren(hasTimeLeft); -@@ -1019,11 +_,18 @@ + this.tickChildren(haveTime); +@@ -1002,11 +_,18 @@ } this.ticksUntilAutosave--; @@ -993,7 +1049,7 @@ this.autoSave(); } - ProfilerFiller profilerFiller = Profiler.get(); + ProfilerFiller profiler = Profiler.get(); + this.server.spark.executeMainThreadTasks(); // Paper - spark + // Paper start - Server Tick Events + long endTime = System.nanoTime(); @@ -1001,31 +1057,31 @@ + new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - this.currentTickStart) / 1000000D), remaining).callEvent(); + // Paper end - Server Tick Events + this.server.spark.tickEnd(((double)(endTime - this.currentTickStart) / 1000000D)); // Paper - spark - profilerFiller.push("tallying"); - long l = Util.getNanos() - nanos; - int i1 = this.tickCount % 100; -@@ -1039,16 +_,16 @@ - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("tick"); + profiler.push("tallying"); + long tickTime = Util.getNanos() - nano; + int tickIndex = this.tickCount % 100; +@@ -1022,16 +_,16 @@ + ProfilerFiller profiler = Profiler.get(); + profiler.push("tick"); this.tickFrame.start(); -- profilerFiller.push("scheduledPacketProcessing"); +- profiler.push("scheduledPacketProcessing"); - this.packetProcessor.processQueuedPackets(); -- profilerFiller.pop(); +- profiler.pop(); + // Paper - improve tick loop - moved into runAllTasksAtTickStart + this.runAllTasksAtTickStart(); // Paper - improve tick loop this.tickServer(sprinting ? () -> false : this::haveTime); this.tickFrame.end(); + this.recordEndOfTick(); // Paper - improve tick loop - profilerFiller.pop(); + profiler.pop(); } private void autoSave() { - this.ticksUntilAutosave = this.computeNextAutosaveInterval(); + this.ticksUntilAutosave = this.autosavePeriod; // CraftBukkit LOGGER.debug("Autosave started"); - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("save"); -@@ -1090,7 +_,7 @@ + ProfilerFiller profiler = Profiler.get(); + profiler.push("save"); +@@ -1073,7 +_,7 @@ private ServerStatus buildServerStatus() { ServerStatus.Players players = this.buildPlayerStatus(); return new ServerStatus( @@ -1034,19 +1090,19 @@ Optional.of(players), Optional.of(ServerStatus.Version.current()), Optional.ofNullable(this.statusIcon), -@@ -1104,7 +_,7 @@ +@@ -1087,7 +_,7 @@ if (this.hidesOnlinePlayers()) { return new ServerStatus.Players(maxPlayers, players.size(), List.of()); } else { -- int min = Math.min(players.size(), 12); -+ int min = Math.min(players.size(), org.spigotmc.SpigotConfig.playerSample); // Paper - PaperServerListPingEvent - ObjectArrayList list = new ObjectArrayList<>(min); - int randomInt = Mth.nextInt(this.random, 0, players.size() - min); - -@@ -1121,18 +_,77 @@ - protected void tickChildren(BooleanSupplier hasTimeLeft) { - ProfilerFiller profilerFiller = Profiler.get(); - this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); +- int sampleSize = Math.min(players.size(), 12); ++ int sampleSize = Math.min(players.size(), org.spigotmc.SpigotConfig.playerSample); // Paper - PaperServerListPingEvent + ObjectArrayList sample = new ObjectArrayList<>(sampleSize); + int offset = Mth.nextInt(this.random, 0, players.size() - sampleSize); + +@@ -1104,6 +_,32 @@ + protected void tickChildren(final BooleanSupplier haveTime) { + ProfilerFiller profiler = Profiler.get(); + this.getPlayerList().getPlayers().forEach(playerx -> playerx.connection.suspendFlushing()); + this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit + // Paper start - Folia scheduler API + ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick(); @@ -1073,65 +1129,50 @@ + // Paper end - Folia scheduler API + io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue(this.tickCount); // Paper + io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper - profilerFiller.push("commandFunctions"); + profiler.push("commandFunctions"); this.getFunctions().tick(); - profilerFiller.popPush("levels"); - this.updateEffectiveRespawnData(); - + profiler.pop(); +@@ -1115,14 +_,28 @@ + + if (this.tickCount % 20 == 0) { + profiler.push("timeSync"); +- this.forceGameTimeSynchronization(); ++ // Paper start - per-world game time ++ for (final ServerLevel level : this.getAllLevels()) { ++ this.playerList.broadcastAll(new ClientboundSetTimePacket(level.getGameTime(), Map.of()), level); ++ } ++ // Paper end - per-world game time + profiler.pop(); ++ } ++ + // CraftBukkit start + // Run tasks that are waiting on processing + while (!this.processQueue.isEmpty()) { + this.processQueue.remove().run(); -+ } -+ -+ // Send time updates to everyone, it will get the right time from the world the player is in. -+ // Paper start - Perf: Optimize time updates -+ for (final ServerLevel level : this.getAllLevels()) { -+ final boolean doDaylight = level.getGameRules().get(GameRules.ADVANCE_TIME); -+ final long dayTime = level.getDayTime(); -+ long worldTime = level.getGameTime(); -+ final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight); -+ for (Player entityhuman : level.players()) { -+ if (!(entityhuman instanceof ServerPlayer) || (tickCount + entityhuman.getId()) % 20 != 0) { -+ continue; -+ } -+ ServerPlayer entityplayer = (ServerPlayer) entityhuman; -+ long playerTime = entityplayer.getPlayerTime(); -+ boolean relativeTime = entityplayer.relativeTime; -+ ClientboundSetTimePacket packet = ((relativeTime || !doDaylight) && playerTime == dayTime) ? worldPacket : -+ new ClientboundSetTimePacket(worldTime, playerTime, relativeTime && doDaylight); -+ entityplayer.connection.send(packet); // Add support for per player time -+ // Paper end - Perf: Optimize time updates -+ } -+ } -+ -+ this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked - for (ServerLevel serverLevel : this.getAllLevels()) { -+ serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent -+ serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent -+ serverLevel.updateLagCompensationTick(); // Paper - lag compensation - profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().identifier()); -+ /* Drop global time updates - if (this.tickCount % 20 == 0) { - profilerFiller.push("timeSync"); - this.synchronizeTime(serverLevel); - profilerFiller.pop(); - } -+ // CraftBukkit end */ - - profilerFiller.push("tick"); + } -@@ -1146,7 +_,9 @@ + profiler.push("levels"); + this.updateEffectiveRespawnData(); - profilerFiller.pop(); - profilerFiller.pop(); -+ serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions ++ this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked + for (ServerLevel level : this.getAllLevels()) { ++ level.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent ++ level.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent ++ level.updateLagCompensationTick(); // Paper - lag compensation + profiler.push(() -> level + " " + level.dimension().identifier()); + profiler.push("tick"); + +@@ -1136,7 +_,9 @@ + + profiler.pop(); + profiler.pop(); ++ level.explosionDensityCache.clear(); // Paper - Optimize explosions } + this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked - profilerFiller.popPush("connection"); + profiler.popPush("connection"); this.tickConnection(); -@@ -1176,9 +_,12 @@ +@@ -1166,9 +_,12 @@ this.serverActivityMonitor.tick(); } @@ -1139,14 +1180,14 @@ - LevelData.RespawnData respawnData = this.worldData.overworldData().getRespawnData(); + // Paper start - per world respawn data - read "server global" respawn data from overworld dimension reference + public void updateEffectiveRespawnData() { - ServerLevel serverLevel = this.findRespawnDimension(); -+ LevelData.RespawnData respawnData = serverLevel.serverLevelData.getRespawnData(); -+ respawnData = respawnData.withLevel(serverLevel.dimension()); + ServerLevel respawnLevel = this.findRespawnDimension(); ++ LevelData.RespawnData respawnData = respawnLevel.serverLevelData.getRespawnData(); ++ respawnData = respawnData.withLevel(respawnLevel.dimension()); + // Paper end - per world respawn data - read "server global" respawn data from overworld dimension reference - this.effectiveRespawnData = serverLevel.getWorldBorderAdjustedRespawnData(respawnData); + this.effectiveRespawnData = respawnLevel.getWorldBorderAdjustedRespawnData(respawnData); } -@@ -1228,6 +_,22 @@ +@@ -1207,6 +_,22 @@ return this.levels.get(dimension); } @@ -1169,37 +1210,37 @@ public Set> levelKeys() { return this.levels.keySet(); } -@@ -1252,7 +_,7 @@ +@@ -1230,7 +_,7 @@ + } - @DontObfuscate public String getServerModName() { - return "vanilla"; + return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper } - public SystemReport fillSystemReport(SystemReport systemReport) { -@@ -1287,7 +_,7 @@ + public ServerClockManager clockManager() { +@@ -1269,7 +_,7 @@ @Override - public void sendSystemMessage(Component message) { + public void sendSystemMessage(final Component message) { - LOGGER.info(message.getString()); + LOGGER.info(io.papermc.paper.adventure.PaperAdventure.ANSI_SERIALIZER.serialize(io.papermc.paper.adventure.PaperAdventure.asAdventure(message))); // Paper - Log message with colors } public KeyPair getKeyPair() { -@@ -1324,11 +_,17 @@ +@@ -1306,11 +_,17 @@ } } -- public void setDifficulty(Difficulty difficulty, boolean forced) { -- if (forced || !this.worldData.isDifficultyLocked()) { +- public void setDifficulty(final Difficulty difficulty, final boolean ignoreLock) { +- if (ignoreLock || !this.worldData.isDifficultyLocked()) { - this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : difficulty); - this.updateMobSpawningFlags(); - this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); + // Paper start - per level difficulty, WorldDifficultyChangeEvent -+ public void setDifficulty(ServerLevel level, Difficulty difficulty, @Nullable CommandSourceStack source, boolean forced) { ++ public void setDifficulty(final ServerLevel level, final Difficulty difficulty, final @Nullable CommandSourceStack source, final boolean ignoreLock) { + net.minecraft.world.level.storage.PrimaryLevelData worldData = level.serverLevelData; -+ if (forced || !worldData.isDifficultyLocked()) { ++ if (ignoreLock || !worldData.isDifficultyLocked()) { + new io.papermc.paper.event.world.WorldDifficultyChangeEvent( + level.getWorld(), source, org.bukkit.craftbukkit.util.CraftDifficulty.toBukkit(difficulty) + ).callEvent(); @@ -1210,7 +1251,7 @@ } } -@@ -1400,10 +_,20 @@ +@@ -1382,10 +_,20 @@ @Override public String getMotd() { @@ -1218,7 +1259,7 @@ + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper - Adventure } - public void setMotd(String motd) { + public void setMotd(final String motd) { + // Paper start - Adventure + this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOr(motd, net.kyori.adventure.text.Component.empty()); + } @@ -1227,28 +1268,28 @@ + return this.motd; + } + -+ public void motd(net.kyori.adventure.text.Component motd) { ++ public void motd(final net.kyori.adventure.text.Component motd) { + // Paper end - Adventure this.motd = motd; } -@@ -1432,9 +_,13 @@ - int i = 0; +@@ -1414,17 +_,20 @@ + int count = 0; - for (ServerPlayer serverPlayer : this.getPlayerList().getPlayers()) { -- if (serverPlayer.setGameMode(gameMode)) { -- i++; + for (ServerPlayer player : this.getPlayerList().getPlayers()) { +- if (player.setGameMode(gameType)) { +- count++; + // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); + if (event == null || event.isCancelled()) { + continue; } -+ i++; ++ count++; + // Paper end - Expand PlayerGameModeChangeEvent } - - return i; -@@ -1442,7 +_,7 @@ +- + return count; + } } public ServerConnectionListener getConnection() { @@ -1257,135 +1298,170 @@ } public boolean isReady() { -@@ -1505,7 +_,7 @@ +@@ -1487,7 +_,7 @@ @Override - public void executeIfPossible(Runnable task) { + public void executeIfPossible(final Runnable command) { if (this.isStopped()) { - throw new RejectedExecutionException("Server already shutting down"); + throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop } else { - super.executeIfPossible(task); + super.executeIfPossible(command); } -@@ -1540,7 +_,14 @@ +@@ -1522,7 +_,16 @@ return this.functionManager; } + // Paper start - Add ServerResourcesReloadedEvent + @Deprecated @io.papermc.paper.annotation.DoNotUse - public CompletableFuture reloadResources(Collection selectedIds) { -+ return this.reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); + public CompletableFuture reloadResources(final Collection packsToEnable) { ++ return this.reloadResources(packsToEnable, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN); + } + -+ public CompletableFuture reloadResources(Collection selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) { ++ public CompletableFuture reloadResources( ++ final Collection packsToEnable, final io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause ++ ) { + // Paper end - Add ServerResourcesReloadedEvent - CompletableFuture completableFuture = CompletableFuture.supplyAsync( - () -> selectedIds.stream().map(this.packRepository::getPack).filter(Objects::nonNull).map(Pack::open).collect(ImmutableList.toImmutableList()), - this -@@ -1548,7 +_,7 @@ + CompletableFuture result = CompletableFuture.supplyAsync( + () -> packsToEnable.stream() + .map(this.packRepository::getPack) +@@ -1534,7 +_,7 @@ .thenCompose( - list -> { - CloseableResourceManager closeableResourceManager = new MultiPackResourceManager(PackType.SERVER_DATA, list); -- List> list1 = TagLoader.loadTagsForExistingRegistries(closeableResourceManager, this.registries.compositeAccess()); -+ List> list1 = TagLoader.loadTagsForExistingRegistries(closeableResourceManager, this.registries.compositeAccess(), io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // Paper - tag lifecycle - add cause + packsToLoad -> { + CloseableResourceManager resources = new MultiPackResourceManager(PackType.SERVER_DATA, packsToLoad); +- List> postponedTags = TagLoader.loadTagsForExistingRegistries(resources, this.registries.compositeAccess()); ++ List> postponedTags = TagLoader.loadTagsForExistingRegistries(resources, this.registries.compositeAccess(), io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // Paper - tag lifecycle - add cause return ReloadableServerResources.loadResources( - closeableResourceManager, + resources, this.registries, -@@ -1569,20 +_,39 @@ +@@ -1554,18 +_,37 @@ + } ) - .thenAcceptAsync( - reloadableResources -> { -+ io.papermc.paper.command.brigadier.PaperBrigadier.moveBukkitCommands(this.resources.managers().getCommands(), reloadableResources.managers().commands); // Paper - this.resources.close(); - this.resources = reloadableResources; -- this.packRepository.setSelected(selectedIds); -+ this.packRepository.setSelected(selectedIds, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above) - WorldDataConfiguration worldDataConfiguration = new WorldDataConfiguration( - getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures() - ); - this.worldData.setDataConfiguration(worldDataConfiguration); - this.resources.managers.updateStaticRegistryTags(); - this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); -- this.getPlayerList().saveAll(); -+ this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes -+ if (Thread.currentThread() != this.serverThread) return; // Paper -+ // Paper start - we don't need to save everything, just advancements -+ // this.getPlayerList().saveAll(); -+ for (final ServerPlayer player : this.getPlayerList().getPlayers()) { -+ player.getAdvancements().save(); -+ } -+ // Paper end - we don't need to save everything, just advancements - this.getPlayerList().reloadResources(); - this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); - this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); - this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); -+ org.bukkit.craftbukkit.block.data.CraftBlockData.reloadCache(); // Paper - cache block data strings; they can be defined by datapacks so refresh it here -+ // Paper start - brigadier command API -+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // reset invalid state for event fire below -+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // call commands event for regular plugins -+ final org.bukkit.craftbukkit.help.SimpleHelpMap helpMap = (org.bukkit.craftbukkit.help.SimpleHelpMap) this.server.getHelpMap(); -+ helpMap.clear(); -+ helpMap.initializeGeneralTopics(); -+ helpMap.initializeCommands(); -+ this.server.syncCommands(); // Refresh commands after event -+ // Paper end -+ new io.papermc.paper.event.server.ServerResourcesReloadedEvent(cause).callEvent(); // Paper - Add ServerResourcesReloadedEvent; fire after everything has been reloaded - }, - this - ); -@@ -1599,7 +_,7 @@ + .thenAcceptAsync(newResources -> { ++ io.papermc.paper.command.brigadier.PaperBrigadier.moveBukkitCommands(this.resources.managers().getCommands(), newResources.managers().commands); // Paper + this.resources.close(); + this.resources = newResources; +- this.packRepository.setSelected(packsToEnable); ++ this.packRepository.setSelected(packsToEnable, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above) + WorldDataConfiguration newConfig = new WorldDataConfiguration(getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); + this.worldData.setDataConfiguration(newConfig); + this.resources.managers.updateComponentsAndStaticRegistryTags(); + this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); +- this.getPlayerList().saveAll(); ++ this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes ++ if (Thread.currentThread() != this.serverThread) return; // Paper ++ // Paper start - we don't need to save everything, just advancements ++ // this.getPlayerList().saveAll(); ++ for (final ServerPlayer player : this.getPlayerList().getPlayers()) { ++ player.getAdvancements().save(); ++ } ++ // Paper end - we don't need to save everything, just advancements + this.getPlayerList().reloadResources(); + this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); + this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); + this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); ++ org.bukkit.craftbukkit.block.data.CraftBlockData.reloadCache(); // Paper - cache block data strings; they can be defined by datapacks so refresh it here ++ // Paper start - brigadier command API ++ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // reset invalid state for event fire below ++ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // call commands event for regular plugins ++ final org.bukkit.craftbukkit.help.SimpleHelpMap helpMap = (org.bukkit.craftbukkit.help.SimpleHelpMap) this.server.getHelpMap(); ++ helpMap.clear(); ++ helpMap.initializeGeneralTopics(); ++ helpMap.initializeCommands(); ++ this.server.syncCommands(); // Refresh commands after event ++ // Paper end ++ new io.papermc.paper.event.server.ServerResourcesReloadedEvent(cause).callEvent(); // Paper - Add ServerResourcesReloadedEvent; fire after everything has been reloaded + }, this); + if (this.isSameThread()) { + this.managedBlock(result::isDone); +@@ -1580,7 +_,7 @@ DataPackConfig dataPackConfig = initialDataConfig.dataPacks(); - FeatureFlagSet featureFlagSet = initMode ? FeatureFlagSet.of() : initialDataConfig.enabledFeatures(); - FeatureFlagSet featureFlagSet1 = initMode ? FeatureFlags.REGISTRY.allFlags() : initialDataConfig.enabledFeatures(); + FeatureFlagSet forcedFeatures = initMode ? FeatureFlagSet.of() : initialDataConfig.enabledFeatures(); + FeatureFlagSet allowedFeatures = initMode ? FeatureFlags.REGISTRY.allFlags() : initialDataConfig.enabledFeatures(); - packRepository.reload(); + packRepository.reload(true); // Paper - will load resource packs if (safeMode) { - return configureRepositoryWithSelection(packRepository, List.of("vanilla"), featureFlagSet, false); + return configureRepositoryWithSelection(packRepository, List.of("vanilla"), forcedFeatures, false); } else { -@@ -1654,7 +_,7 @@ +@@ -1635,7 +_,7 @@ private static WorldDataConfiguration configureRepositoryWithSelection( - PackRepository packRepository, Collection selectedPacks, FeatureFlagSet enabledFeatures, boolean safeMode + final PackRepository packRepository, final Collection selected, final FeatureFlagSet forcedFeatures, final boolean disableInactive ) { -- packRepository.setSelected(selectedPacks); -+ packRepository.setSelected(selectedPacks, true); // Paper - add pendingReload flag to determine required pack loading - before the initial server load - enableForcedFeaturePacks(packRepository, enabledFeatures); - DataPackConfig selectedPacks1 = getSelectedPacks(packRepository, safeMode); - FeatureFlagSet featureFlagSet = packRepository.getRequestedFeatureFlags().join(enabledFeatures); -@@ -1686,7 +_,7 @@ +- packRepository.setSelected(selected); ++ packRepository.setSelected(selected, true); // Paper - add pendingReload flag to determine required pack loading - before the initial server load + enableForcedFeaturePacks(packRepository, forcedFeatures); + DataPackConfig packConfig = getSelectedPacks(packRepository, disableInactive); + FeatureFlagSet packRequestedFeatures = packRepository.getRequestedFeatureFlags().join(forcedFeatures); +@@ -1667,7 +_,7 @@ } } -- packRepository.setSelected(set); -+ packRepository.setSelected(set, true); // Paper - add pendingReload flag to determine required pack loading - before the initial server start +- packRepository.setSelected(selected); ++ packRepository.setSelected(selected, true); // Paper - add pendingReload flag to determine required pack loading - before the initial server start } } -@@ -1703,8 +_,8 @@ +@@ -1684,8 +_,8 @@ UserWhiteList whiteList = playerList.getWhiteList(); - for (ServerPlayer serverPlayer : Lists.newArrayList(playerList.getPlayers())) { -- if (!whiteList.isWhiteListed(serverPlayer.nameAndId())) { -- serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.not_whitelisted")); -+ if (!whiteList.isWhiteListed(serverPlayer.nameAndId()) && !this.getPlayerList().isOp(serverPlayer.nameAndId())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) -+ serverPlayer.connection.disconnect(net.kyori.adventure.text.Component.text(org.spigotmc.SpigotConfig.whitelistMessage), org.bukkit.event.player.PlayerKickEvent.Cause.WHITELIST); // Paper - use configurable message & kick event cause + for (ServerPlayer player : Lists.newArrayList(playerList.getPlayers())) { +- if (!whiteList.isWhiteListed(player.nameAndId())) { +- player.connection.disconnect(Component.translatable("multiplayer.disconnect.not_whitelisted")); ++ if (!whiteList.isWhiteListed(player.nameAndId()) && !this.getPlayerList().isOp(player.nameAndId())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) ++ player.connection.disconnect(net.kyori.adventure.text.Component.text(org.spigotmc.SpigotConfig.whitelistMessage), org.bukkit.event.player.PlayerKickEvent.Cause.WHITELIST); // Paper - use configurable message & kick event cause } } } -@@ -1734,12 +_,12 @@ +@@ -1715,12 +_,12 @@ } public ServerLevel findRespawnDimension() { - LevelData.RespawnData respawnData = this.getWorldData().overworldData().getRespawnData(); -- ResourceKey resourceKey = respawnData.dimension(); -+ ResourceKey resourceKey = ((net.minecraft.world.level.storage.PrimaryLevelData) this.getWorldData().overworldData()).respawnDimension; // Paper - per world respawn data - read "server global" respawn data from overworld dimension reference - ServerLevel level = this.getLevel(resourceKey); - return level != null ? level : this.overworld(); +- ResourceKey respawnDimension = respawnData.dimension(); ++ ResourceKey respawnDimension = this.getWorldData().overworldData().getRespawnData().dimension(); // Paper - per world respawn data - read "server global" respawn data from overworld dimension reference + ServerLevel respawnLevel = this.getLevel(respawnDimension); + return respawnLevel != null ? respawnLevel : this.overworld(); } + @io.papermc.paper.annotation.DoNotUse @Deprecated(forRemoval = true) // Paper - per world respawn data - set through Level - public void setRespawnData(LevelData.RespawnData respawnData) { - ServerLevelData serverLevelData = this.worldData.overworldData(); - LevelData.RespawnData respawnData1 = serverLevelData.getRespawnData(); -@@ -1941,6 +_,17 @@ + public void setRespawnData(final LevelData.RespawnData respawnData) { + ServerLevelData levelData = this.worldData.overworldData(); + LevelData.RespawnData oldRespawnData = levelData.getRespawnData(); +@@ -1788,17 +_,20 @@ + return this.randomSequences; + } + +- public void setWeatherParameters(final int clearTime, final int rainTime, final boolean raining, final boolean thundering) { +- WeatherData weatherData = this.getWeatherData(); ++ // Paper start - per-level WeatherData ++ public void setWeatherParameters(final ServerLevel level, final int clearTime, final int rainTime, final boolean raining, final boolean thundering) { ++ WeatherData weatherData = level.getWeatherData(); ++ // Paper end - per-level WeatherData + weatherData.setClearWeatherTime(clearTime); + weatherData.setRainTime(rainTime); + weatherData.setThunderTime(rainTime); +- weatherData.setRaining(raining); +- weatherData.setThundering(thundering); ++ weatherData.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.COMMAND); // Paper - per-level WeatherData ++ weatherData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.COMMAND); // Paper - per-level WeatherData + } + ++ @Deprecated(forRemoval = true) @io.papermc.paper.annotation.DoNotUse // Paper + public WeatherData getWeatherData() { +- return this.weatherData; ++ throw new UnsupportedOperationException("Use ServerLevel.getWeatherData() instead"); // Paper + } + + public boolean isEnforceWhitelist() { +@@ -1889,7 +_,7 @@ + private void dumpGameRules(final Path path) throws IOException { + try (Writer output = Files.newBufferedWriter(path)) { + final List entries = Lists.newArrayList(); +- final GameRules gameRules = this.getGameRules(); ++ final GameRules gameRules = this.overworld().getGameRules(); // Paper - per-level GameRules + gameRules.visitGameRuleTypes(new GameRuleTypeVisitor() { + { + Objects.requireNonNull(MinecraftServer.this); +@@ -1951,6 +_,17 @@ } } @@ -1403,19 +1479,19 @@ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { this.metricsRecorder = ActiveMetricsRecorder.createStarted( -@@ -2061,16 +_,22 @@ +@@ -2071,16 +_,22 @@ } - public void logChatMessage(Component content, ChatType.Bound boundChatType, @Nullable String header) { -- String string = boundChatType.decorate(content).getString(); + public void logChatMessage(final Component message, final ChatType.Bound chatType, final @Nullable String tag) { +- String decoratedMessage = chatType.decorate(message).getString(); + // Paper start -+ net.kyori.adventure.text.Component string = io.papermc.paper.adventure.PaperAdventure.asAdventure(boundChatType.decorate(content)); - if (header != null) { -- LOGGER.info("[{}] {}", header, string); -+ COMPONENT_LOGGER.info("[{}] {}", header, string); ++ net.kyori.adventure.text.Component decoratedMessage = io.papermc.paper.adventure.PaperAdventure.asAdventure(chatType.decorate(message)); + if (tag != null) { +- LOGGER.info("[{}] {}", tag, decoratedMessage); ++ COMPONENT_LOGGER.info("[{}] {}", tag, decoratedMessage); } else { -- LOGGER.info("{}", string); -+ COMPONENT_LOGGER.info("{}", string); +- LOGGER.info("{}", decoratedMessage); ++ COMPONENT_LOGGER.info("{}", decoratedMessage); + // Paper end } } @@ -1430,7 +1506,7 @@ } public boolean logIPs() { -@@ -2081,8 +_,9 @@ +@@ -2091,8 +_,9 @@ LOGGER.debug("Received custom click action {} with payload {}", id, payload.orElse(null)); } @@ -1440,37 +1516,37 @@ + throw new UnsupportedOperationException(); // Paper - per level load listener } - public boolean setAutoSave(boolean autoSave) { -@@ -2108,12 +_,14 @@ + public boolean setAutoSave(final boolean enable) { +@@ -2118,12 +_,14 @@ return false; } -- public void onGameRuleChanged(GameRule rule, T value) { +- public void onGameRuleChanged(final GameRule rule, final T value) { - this.notificationManager().onGameRuleChanged(rule, value); + // Paper start - per-world game rules -+ public void onGameRuleChanged(ServerLevel serverLevel, GameRule rule, T value) { -+ this.notificationManager().onGameRuleChanged(serverLevel, rule, value); ++ public void onGameRuleChanged(final ServerLevel level, final GameRule rule, final T value) { ++ this.notificationManager().onGameRuleChanged(level, rule, value); + // Paper end - per-world game rules if (rule == GameRules.REDUCED_DEBUG_INFO) { - byte b = (byte)((Boolean)value ? 22 : 23); + byte event = (byte)((Boolean)value ? 22 : 23); -- for (ServerPlayer serverPlayer : this.getPlayerList().getPlayers()) { -+ for (ServerPlayer serverPlayer : serverLevel.players()) { // Paper - per-world game rules - serverPlayer.connection.send(new ClientboundEntityEventPacket(serverPlayer, b)); +- for (ServerPlayer player : this.getPlayerList().getPlayers()) { ++ for (ServerPlayer player : level.players()) { // Paper - per-world game rules + player.connection.send(new ClientboundEntityEventPacket(player, event)); } } else if (rule == GameRules.LIMITED_CRAFTING || rule == GameRules.IMMEDIATE_RESPAWN) { -@@ -2121,18 +_,18 @@ +@@ -2131,19 +_,20 @@ ? ClientboundGameEventPacket.LIMITED_CRAFTING : ClientboundGameEventPacket.IMMEDIATE_RESPAWN; - ClientboundGameEventPacket clientboundGameEventPacket = new ClientboundGameEventPacket(type, (Boolean)value ? 1.0F : 0.0F); -- this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.send(clientboundGameEventPacket)); -+ serverLevel.players().forEach(serverPlayer1 -> serverPlayer1.connection.send(clientboundGameEventPacket)); // Paper - per-world game rules + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(eventType, (Boolean)value ? 1.0F : 0.0F); +- this.getPlayerList().getPlayers().forEach(playerx -> playerx.connection.send(packet)); ++ level.players().forEach(playerx -> playerx.connection.send(packet)); // Paper - per-world game rules } else if (rule == GameRules.LOCATOR_BAR) { -- this.getAllLevels().forEach(serverLevel -> { -+ // this.getAllLevels().forEach(serverLevel -> { // Paper - per-world game rules - ServerWaypointManager waypointManager = serverLevel.getWaypointManager(); +- this.getAllLevels().forEach(level -> { ++ // this.getAllLevels().forEach(level -> { // Paper - per-world game rules + ServerWaypointManager waypointManager = level.getWaypointManager(); if ((Boolean)value) { - serverLevel.players().forEach(waypointManager::updatePlayer); + level.players().forEach(waypointManager::updatePlayer); } else { waypointManager.breakAllConnections(); } @@ -1478,11 +1554,30 @@ + // }); // Paper - per-world game rules } else if (rule == GameRules.SPAWN_MONSTERS) { - this.updateMobSpawningFlags(); -+ serverLevel.setSpawnSettings(serverLevel.isSpawningMonsters()); // Paper - per-world game rules ++ level.setSpawnSettings(level.isSpawningMonsters()); // Paper - per-world game rules + } else if (rule == GameRules.ADVANCE_TIME) { ++ // TODO - snapshot - time handling + this.getPlayerList().broadcastAll(this.clockManager().createFullSyncPacket()); } } +@@ -2157,12 +_,14 @@ + return this.savedDataStorage; + } + ++ @Deprecated(forRemoval = true) @io.papermc.paper.annotation.DoNotUse + public TimerQueue getScheduledEvents() { +- return this.scheduledEvents; ++ throw new UnsupportedOperationException("Use ServerLevel.getScheduledEvents() instead"); // Paper + } + ++ @Deprecated(forRemoval = true) @io.papermc.paper.annotation.DoNotUse // Paper + public GameRules getGameRules() { +- return this.gameRules; ++ throw new UnsupportedOperationException("Use ServerLevel.getGameRules() instead"); // Paper + } -@@ -2267,4 +_,53 @@ + public boolean acceptsTransfers() { +@@ -2312,4 +_,53 @@ }; } } diff --git a/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch b/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch index 91cc5562a305..f8391f805185 100644 --- a/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch @@ -15,51 +15,51 @@ private final Codec codec; + public final Map, Set>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage - public PlayerAdvancements(DataFixer dataFixer, PlayerList playerList, ServerAdvancementManager manager, Path playerSavePath, ServerPlayer player) { - this.playerList = playerList; -@@ -126,6 +_,7 @@ + public PlayerAdvancements( + final DataFixer dataFixer, final PlayerList playerList, final ServerAdvancementManager manager, final Path playerSavePath, final ServerPlayer player +@@ -128,6 +_,7 @@ } public void save() { + if (org.spigotmc.SpigotConfig.disableAdvancementSaving) return; // Spigot - JsonElement jsonElement = this.codec.encodeStart(JsonOps.INSTANCE, this.asData()).getOrThrow(); + JsonElement json = this.codec.encodeStart(JsonOps.INSTANCE, this.asData()).getOrThrow(); try { -@@ -143,6 +_,7 @@ - data.forEach((path, progress) -> { - AdvancementHolder advancementHolder = advancementManager.get(path); - if (advancementHolder == null) { -+ if (!path.getNamespace().equals(Identifier.DEFAULT_NAMESPACE)) return; // CraftBukkit - LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", path, this.playerSavePath); +@@ -145,6 +_,7 @@ + data.forEach((id, progress) -> { + AdvancementHolder advancement = manager.get(id); + if (advancement == null) { ++ if (!id.getNamespace().equals(Identifier.DEFAULT_NAMESPACE)) return; // CraftBukkit + LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", id, this.playerSavePath); } else { - this.startProgress(advancementHolder, progress); -@@ -167,14 +_,31 @@ - AdvancementProgress orStartProgress = this.getOrStartProgress(advancement); - boolean isDone = orStartProgress.isDone(); - if (orStartProgress.grantProgress(criterionKey)) { + this.startProgress(advancement, progress); +@@ -169,14 +_,31 @@ + AdvancementProgress progress = this.getOrStartProgress(holder); + boolean wasDone = progress.isDone(); + if (progress.grantProgress(criterion)) { + // Paper start - Add PlayerAdvancementCriterionGrantEvent -+ if (!new com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent(this.player.getBukkitEntity(), advancement.toBukkit(), criterionKey).callEvent()) { -+ orStartProgress.revokeProgress(criterionKey); ++ if (!new com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent(this.player.getBukkitEntity(), holder.toBukkit(), criterion).callEvent()) { ++ progress.revokeProgress(criterion); + return false; + } + // Paper end - Add PlayerAdvancementCriterionGrantEvent - this.unregisterListeners(advancement); - this.progressChanged.add(advancement); - flag = true; - if (!isDone && orStartProgress.isDone()) { + this.unregisterListeners(holder); + this.progressChanged.add(holder); + result = true; + if (!wasDone && progress.isDone()) { + // Paper start - Add Adventure message to PlayerAdvancementDoneEvent -+ final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { ++ final net.kyori.adventure.text.Component message = holder.value().display().flatMap(info -> { + return java.util.Optional.ofNullable( -+ info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null ++ info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(holder, this.player)) : null + ); + }).orElse(null); -+ final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit(), message); ++ final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), holder.toBukkit(), message); + this.player.level().getCraftServer().getPluginManager().callEvent(event); // CraftBukkit + // Paper end - advancement.value().rewards().grant(this.player); - advancement.value().display().ifPresent(displayInfo -> { -- if (displayInfo.shouldAnnounceChat() && this.player.level().getGameRules().get(GameRules.SHOW_ADVANCEMENT_MESSAGES)) { -- this.playerList.broadcastSystemMessage(displayInfo.getType().createAnnouncement(advancement, this.player), false); + holder.value().rewards().grant(this.player); + holder.value().display().ifPresent(display -> { +- if (display.shouldAnnounceChat() && this.player.level().getGameRules().get(GameRules.SHOW_ADVANCEMENT_MESSAGES)) { +- this.playerList.broadcastSystemMessage(display.getType().createAnnouncement(holder, this.player), false); + // Paper start - Add Adventure message to PlayerAdvancementDoneEvent + if (event.message() != null && this.player.level().getGameRules().get(GameRules.SHOW_ADVANCEMENT_MESSAGES)) { + this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); @@ -67,12 +67,12 @@ } }); } -@@ -245,7 +_,7 @@ - public void flushDirty(ServerPlayer player, boolean showAdvancements) { +@@ -247,7 +_,7 @@ + public void flushDirty(final ServerPlayer player, final boolean showAdvancements) { if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) { - Map map = new HashMap<>(); -- Set set = new HashSet<>(); -+ Set set = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically. - Set set1 = new HashSet<>(); + Map progress = new HashMap<>(); +- Set added = new HashSet<>(); ++ Set added = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically. + Set removed = new HashSet<>(); - for (AdvancementNode advancementNode : this.rootsToUpdate) { + for (AdvancementNode root : this.rootsToUpdate) { diff --git a/paper-server/patches/sources/net/minecraft/server/ReloadableServerRegistries.java.patch b/paper-server/patches/sources/net/minecraft/server/ReloadableServerRegistries.java.patch index 17d2976357a1..2408760e9830 100644 --- a/paper-server/patches/sources/net/minecraft/server/ReloadableServerRegistries.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ReloadableServerRegistries.java.patch @@ -1,38 +1,37 @@ --- a/net/minecraft/server/ReloadableServerRegistries.java +++ b/net/minecraft/server/ReloadableServerRegistries.java -@@ -46,8 +_,9 @@ - List> list = TagLoader.buildUpdatedLookups(registryAccess.getAccessForLoading(RegistryLayer.RELOADABLE), postponedTags); - HolderLookup.Provider provider = HolderLookup.Provider.create(list.stream()); - RegistryOps registryOps = provider.createSerializationContext(JsonOps.INSTANCE); -+ final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(registryOps.lookupProvider); // Paper - List>> list1 = LootDataType.values() -- .map(lootDataType -> scheduleRegistryLoad((LootDataType)lootDataType, registryOps, resourceManager, backgroundExecutor)) -+ .map(lootDataType -> scheduleRegistryLoad((LootDataType)lootDataType, registryOps, resourceManager, backgroundExecutor, conversions)) // Paper +@@ -48,8 +_,9 @@ + ); + HolderLookup.Provider loadingContextWithTags = HolderLookup.Provider.create(contextRegistriesWithTags.stream()); + RegistryOps ops = loadingContextWithTags.createSerializationContext(JsonOps.INSTANCE); ++ final io.papermc.paper.registry.data.util.Conversions conversions = new io.papermc.paper.registry.data.util.Conversions(ops.lookupProvider); // Paper + List>> registryLoads = LootDataType.values() +- .map(type -> scheduleRegistryLoad((LootDataType)type, ops, manager, executor)) ++ .map(type -> scheduleRegistryLoad((LootDataType)type, ops, manager, executor, conversions)) // Paper .toList(); - CompletableFuture>> completableFuture = Util.sequence(list1); - return completableFuture.thenApplyAsync( -@@ -56,19 +_,20 @@ + CompletableFuture>> sequence = Util.sequence(registryLoads); + return sequence.thenApplyAsync( +@@ -58,14 +_,20 @@ } - private static CompletableFuture> scheduleRegistryLoad( -- LootDataType lootDataType, RegistryOps ops, ResourceManager resourceManager, Executor backgroundExecutor -+ LootDataType lootDataType, RegistryOps ops, ResourceManager resourceManager, Executor backgroundExecutor, io.papermc.paper.registry.data.util.Conversions conversions // Paper + private static CompletableFuture> scheduleRegistryLoad( +- final LootDataType type, final RegistryOps ops, final ResourceManager manager, final Executor taskExecutor ++ final LootDataType type, final RegistryOps ops, final ResourceManager manager, final Executor taskExecutor, final io.papermc.paper.registry.data.util.Conversions conversions // Paper ) { - return CompletableFuture.supplyAsync( - () -> { - WritableRegistry writableRegistry = new MappedRegistry<>(lootDataType.registryKey(), Lifecycle.experimental()); -+ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(writableRegistry); // Paper - register reloadable registry - Map map = new HashMap<>(); - SimpleJsonResourceReloadListener.scanDirectory(resourceManager, lootDataType.registryKey(), ops, lootDataType.codec(), map); - map.forEach( -- (identifier, object) -> writableRegistry.register( -- ResourceKey.create(lootDataType.registryKey(), identifier), (T)object, DEFAULT_REGISTRATION_INFO -+ (identifier, object) -> io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(writableRegistry, // Paper - register with listeners -+ ResourceKey.create(lootDataType.registryKey(), identifier), (T)object, DEFAULT_REGISTRATION_INFO, conversions // Paper - register with listeners - ) - ); -- TagLoader.loadTagsForRegistry(resourceManager, writableRegistry); -+ TagLoader.loadTagsForRegistry(resourceManager, writableRegistry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // Paper - tag life cycle - reload - return writableRegistry; - }, - backgroundExecutor + return CompletableFuture.supplyAsync(() -> { + WritableRegistry registry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(registry); // Paper - register reloadable registry + Map elements = new HashMap<>(); + SimpleJsonResourceReloadListener.scanDirectory(manager, type.registryKey(), ops, type.codec(), elements); +- elements.forEach((id, element) -> registry.register(ResourceKey.create(type.registryKey(), id), (T)element, DEFAULT_REGISTRATION_INFO)); +- TagLoader.loadTagsForRegistry(manager, registry); ++ // Paper start - register with listeners ++ elements.forEach((id, element) -> { ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners( ++ registry, ResourceKey.create(type.registryKey(), id), (T)element, DEFAULT_REGISTRATION_INFO, conversions); ++ }); ++ // Paper end - register with listeners ++ TagLoader.loadTagsForRegistry(manager, registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // Paper - tag life cycle - reload + return registry; + }, taskExecutor); + } diff --git a/paper-server/patches/sources/net/minecraft/server/ReloadableServerResources.java.patch b/paper-server/patches/sources/net/minecraft/server/ReloadableServerResources.java.patch index 37f4eb620c5e..16ad8fec5242 100644 --- a/paper-server/patches/sources/net/minecraft/server/ReloadableServerResources.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ReloadableServerResources.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/server/ReloadableServerResources.java +++ b/net/minecraft/server/ReloadableServerResources.java -@@ -39,7 +_,9 @@ - this.fullRegistryHolder = new ReloadableServerRegistries.Holder(registryAccess.compositeAccess()); +@@ -44,7 +_,9 @@ this.postponedTags = postponedTags; - this.recipes = new RecipeManager(registries); -- this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures)); -+ this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration -+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(registries, enabledFeatures)); // Paper - Brigadier Command API + this.newComponents = newComponents; + this.recipes = new RecipeManager(loadingContext); +- this.commands = new Commands(commandSelection, CommandBuildContext.simple(loadingContext, enabledFeatures)); ++ this.commands = new Commands(commandSelection, CommandBuildContext.simple(loadingContext, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration ++ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(loadingContext, enabledFeatures)); // Paper - Brigadier Command API + io.papermc.paper.command.PaperCommands.registerCommands(); // Paper - this.advancements = new ServerAdvancementManager(registries); - this.functionLibrary = new ServerFunctionLibrary(permissions, this.commands.getDispatcher()); + this.advancements = new ServerAdvancementManager(loadingContext); + this.functionLibrary = new ServerFunctionLibrary(functionCompilationPermissions, this.commands.getDispatcher()); } -@@ -84,6 +_,14 @@ - ReloadableServerResources reloadableServerResources = new ReloadableServerResources( - loadResult.layers(), loadResult.lookupWithUpdatedTags(), enabledFeatures, commandSelection, postponedTags, permissions - ); -+ // Paper start - call commands event for bootstraps -+ //noinspection ConstantValue -+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent( -+ io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, -+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, -+ io.papermc.paper.plugin.bootstrap.BootstrapContext.class, -+ MinecraftServer.getServer() == null ? io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL : io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); -+ // Paper end - call commands event - return SimpleReloadInstance.create( - resourceManager, - reloadableServerResources.listeners(), +@@ -99,6 +_,14 @@ + functionCompilationPermissions, + (List>)pendingComponents + ); ++ // Paper start - call commands event for bootstraps ++ //noinspection ConstantValue ++ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent( ++ io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, ++ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, ++ io.papermc.paper.plugin.bootstrap.BootstrapContext.class, ++ MinecraftServer.getServer() == null ? io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL : io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); ++ // Paper end - call commands event + return SimpleReloadInstance.create( + resourceManager, + result.listeners(), diff --git a/paper-server/patches/sources/net/minecraft/server/ServerAdvancementManager.java.patch b/paper-server/patches/sources/net/minecraft/server/ServerAdvancementManager.java.patch index 3f0820b171c8..a31bc2aeb710 100644 --- a/paper-server/patches/sources/net/minecraft/server/ServerAdvancementManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ServerAdvancementManager.java.patch @@ -10,22 +10,22 @@ private final HolderLookup.Provider registries; @@ -35,12 +_,18 @@ - protected void apply(Map object, ResourceManager resourceManager, ProfilerFiller profiler) { + protected void apply(final Map preparations, final ResourceManager manager, final ProfilerFiller profiler) { Builder builder = ImmutableMap.builder(); - object.forEach((identifier, advancement) -> { + preparations.forEach((id, advancement) -> { + // Spigot start -+ if (org.spigotmc.SpigotConfig.disabledAdvancements != null && (org.spigotmc.SpigotConfig.disabledAdvancements.contains("*") || org.spigotmc.SpigotConfig.disabledAdvancements.contains(identifier.toString()) || org.spigotmc.SpigotConfig.disabledAdvancements.contains(identifier.getNamespace()))) { ++ if (org.spigotmc.SpigotConfig.disabledAdvancements != null && (org.spigotmc.SpigotConfig.disabledAdvancements.contains("*") || org.spigotmc.SpigotConfig.disabledAdvancements.contains(id.toString()) || org.spigotmc.SpigotConfig.disabledAdvancements.contains(id.getNamespace()))) { + return; + } + // Spigot end - this.validate(identifier, advancement); - builder.put(identifier, new AdvancementHolder(identifier, advancement)); + this.validate(id, advancement); + builder.put(id, new AdvancementHolder(id, advancement)); }); - this.advancements = builder.buildOrThrow(); + this.advancements = new java.util.HashMap<>(builder.buildOrThrow()); // CraftBukkit - SPIGOT-7734: mutable - AdvancementTree advancementTree = new AdvancementTree(); - advancementTree.addAll(this.advancements.values()); -+ LOGGER.info("Loaded {} advancements", advancementTree.nodes().size()); // Paper - Improve logging and errors; moved from AdvancementTree#addAll + AdvancementTree tree = new AdvancementTree(); + tree.addAll(this.advancements.values()); ++ LOGGER.info("Loaded {} advancements", tree.nodes().size()); // Paper - Improve logging and errors; moved from AdvancementTree#addAll - for (AdvancementNode advancementNode : advancementTree.roots()) { - if (advancementNode.holder().value().display().isPresent()) { + for (AdvancementNode root : tree.roots()) { + if (root.holder().value().display().isPresent()) { diff --git a/paper-server/patches/sources/net/minecraft/server/ServerFunctionLibrary.java.patch b/paper-server/patches/sources/net/minecraft/server/ServerFunctionLibrary.java.patch index 5b4c62b4b947..9b7775ebb2f8 100644 --- a/paper-server/patches/sources/net/minecraft/server/ServerFunctionLibrary.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ServerFunctionLibrary.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/ServerFunctionLibrary.java +++ b/net/minecraft/server/ServerFunctionLibrary.java -@@ -108,7 +_,7 @@ +@@ -111,7 +_,7 @@ return null; }).join()); - this.functions = builder.build(); -- this.tags = this.tagsLoader.build((Map>)pair.getFirst()); -+ this.tags = this.tagsLoader.build((Map>)pair.getFirst(), null); // Paper - command function tags are not implemented yet + this.functions = newFunctions.build(); +- this.tags = this.tagsLoader.build((Map>)data.getFirst()); ++ this.tags = this.tagsLoader.build((Map>)data.getFirst(), null); // Paper - command function tags are not implemented yet }, - gameExecutor + reloadExecutor ); diff --git a/paper-server/patches/sources/net/minecraft/server/ServerScoreboard.java.patch b/paper-server/patches/sources/net/minecraft/server/ServerScoreboard.java.patch index a88e27ddb03e..f515b4a2c308 100644 --- a/paper-server/patches/sources/net/minecraft/server/ServerScoreboard.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ServerScoreboard.java.patch @@ -1,42 +1,42 @@ --- a/net/minecraft/server/ServerScoreboard.java +++ b/net/minecraft/server/ServerScoreboard.java @@ -51,9 +_,7 @@ - protected void onScoreChanged(ScoreHolder scoreHolder, Objective objective, Score score) { - super.onScoreChanged(scoreHolder, objective, score); + protected void onScoreChanged(final ScoreHolder owner, final Objective objective, final Score score) { + super.onScoreChanged(owner, objective, score); if (this.trackedObjectives.contains(objective)) { - this.server - .getPlayerList() - .broadcastAll( + this.broadcastAll( // CraftBukkit new ClientboundSetScorePacket( - scoreHolder.getScoreboardName(), + owner.getScoreboardName(), objective.getName(), @@ -76,7 +_,7 @@ @Override - public void onPlayerRemoved(ScoreHolder scoreHolder) { - super.onPlayerRemoved(scoreHolder); -- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(scoreHolder.getScoreboardName(), null)); -+ this.broadcastAll(new ClientboundResetScorePacket(scoreHolder.getScoreboardName(), null)); // CraftBukkit + public void onPlayerRemoved(final ScoreHolder player) { + super.onPlayerRemoved(player); +- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(player.getScoreboardName(), null)); ++ this.broadcastAll(new ClientboundResetScorePacket(player.getScoreboardName(), null)); // CraftBukkit this.setDirty(); } @@ -84,7 +_,7 @@ - public void onPlayerScoreRemoved(ScoreHolder scoreHolder, Objective objective) { - super.onPlayerScoreRemoved(scoreHolder, objective); + public void onPlayerScoreRemoved(final ScoreHolder player, final Objective objective) { + super.onPlayerScoreRemoved(player, objective); if (this.trackedObjectives.contains(objective)) { -- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(scoreHolder.getScoreboardName(), objective.getName())); -+ this.broadcastAll(new ClientboundResetScorePacket(scoreHolder.getScoreboardName(), objective.getName())); // CraftBukkit +- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(player.getScoreboardName(), objective.getName())); ++ this.broadcastAll(new ClientboundResetScorePacket(player.getScoreboardName(), objective.getName())); // CraftBukkit } this.setDirty(); @@ -96,7 +_,7 @@ super.setDisplayObjective(slot, objective); - if (displayObjective != objective && displayObjective != null) { - if (this.getObjectiveDisplaySlotCount(displayObjective) > 0) { + if (old != objective && old != null) { + if (this.getObjectiveDisplaySlotCount(old) > 0) { - this.server.getPlayerList().broadcastAll(new ClientboundSetDisplayObjectivePacket(slot, objective)); + this.broadcastAll(new ClientboundSetDisplayObjectivePacket(slot, objective)); // CraftBukkit } else { - this.stopTrackingObjective(displayObjective); + this.stopTrackingObjective(old); } @@ -104,7 +_,7 @@ @@ -49,16 +49,16 @@ } @@ -116,9 +_,7 @@ @Override - public boolean addPlayerToTeam(String playerName, PlayerTeam team) { - if (super.addPlayerToTeam(playerName, team)) { + public boolean addPlayerToTeam(final String player, final PlayerTeam team) { + if (super.addPlayerToTeam(player, team)) { - this.server - .getPlayerList() -- .broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.Action.ADD)); -+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.Action.ADD)); // CraftBukkit - this.updatePlayerWaypoint(playerName); +- .broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, player, ClientboundSetPlayerTeamPacket.Action.ADD)); ++ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, player, ClientboundSetPlayerTeamPacket.Action.ADD)); // CraftBukkit + this.updatePlayerWaypoint(player); this.setDirty(); return true; -@@ -127,16 +_,44 @@ +@@ -127,14 +_,44 @@ } } @@ -82,13 +82,11 @@ + // Paper end - Multiple Entries with Scoreboards + @Override - public void removePlayerFromTeam(String playerName, PlayerTeam team) { - super.removePlayerFromTeam(playerName, team); -- this.server -- .getPlayerList() -- .broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.Action.REMOVE)); -+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.Action.REMOVE)); // CraftBukkit - this.updatePlayerWaypoint(playerName); + public void removePlayerFromTeam(final String player, final PlayerTeam team) { + super.removePlayerFromTeam(player, team); +- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, player, ClientboundSetPlayerTeamPacket.Action.REMOVE)); ++ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, player, ClientboundSetPlayerTeamPacket.Action.REMOVE)); // CraftBukkit + this.updatePlayerWaypoint(player); this.setDirty(); } @@ -104,10 +102,10 @@ + // Paper end - Multiple Entries with Scoreboards + @Override - public void onObjectiveAdded(Objective objective) { + public void onObjectiveAdded(final Objective objective) { super.onObjectiveAdded(objective); -@@ -147,7 +_,7 @@ - public void onObjectiveChanged(Objective objective) { +@@ -145,7 +_,7 @@ + public void onObjectiveChanged(final Objective objective) { super.onObjectiveChanged(objective); if (this.trackedObjectives.contains(objective)) { - this.server.getPlayerList().broadcastAll(new ClientboundSetObjectivePacket(objective, ClientboundSetObjectivePacket.METHOD_CHANGE)); @@ -115,9 +113,9 @@ } this.setDirty(); -@@ -166,14 +_,14 @@ +@@ -164,14 +_,14 @@ @Override - public void onTeamAdded(PlayerTeam team) { + public void onTeamAdded(final PlayerTeam team) { super.onTeamAdded(team); - this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); + this.broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true)); // CraftBukkit @@ -125,40 +123,40 @@ } @Override - public void onTeamChanged(PlayerTeam team) { + public void onTeamChanged(final PlayerTeam team) { super.onTeamChanged(team); - this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false)); + this.broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, false)); // CraftBukkit this.updateTeamWaypoints(team); this.setDirty(); } -@@ -181,7 +_,7 @@ +@@ -179,7 +_,7 @@ @Override - public void onTeamRemoved(PlayerTeam team) { + public void onTeamRemoved(final PlayerTeam team) { super.onTeamRemoved(team); - this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createRemovePacket(team)); + this.broadcastAll(ClientboundSetPlayerTeamPacket.createRemovePacket(team)); // CraftBukkit this.updateTeamWaypoints(team); this.setDirty(); } -@@ -226,6 +_,7 @@ - List> startTrackingPackets = this.getStartTrackingPackets(objective); +@@ -220,6 +_,7 @@ + List> packets = this.getStartTrackingPackets(objective); - for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) { -+ if (serverPlayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board - for (Packet packet : startTrackingPackets) { - serverPlayer.connection.send(packet); + for (ServerPlayer player : this.server.getPlayerList().getPlayers()) { ++ if (player.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board + for (Packet packet : packets) { + player.connection.send(packet); } -@@ -251,6 +_,7 @@ - List> stopTrackingPackets = this.getStopTrackingPackets(objective); +@@ -245,6 +_,7 @@ + List> packets = this.getStopTrackingPackets(objective); - for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) { -+ if (serverPlayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board - for (Packet packet : stopTrackingPackets) { - serverPlayer.connection.send(packet); + for (ServerPlayer player : this.server.getPlayerList().getPlayers()) { ++ if (player.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board + for (Packet packet : packets) { + player.connection.send(packet); } -@@ -287,4 +_,13 @@ - .forEach(serverPlayer -> serverLevel.getWaypointManager().remakeConnections(serverPlayer)); +@@ -281,4 +_,13 @@ + .forEach(player -> level.getWaypointManager().remakeConnections(player)); } } + // CraftBukkit start - Send to players diff --git a/paper-server/patches/sources/net/minecraft/server/ServerTickRateManager.java.patch b/paper-server/patches/sources/net/minecraft/server/ServerTickRateManager.java.patch index ca15194f68e6..2c6809bc1715 100644 --- a/paper-server/patches/sources/net/minecraft/server/ServerTickRateManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/ServerTickRateManager.java.patch @@ -6,29 +6,31 @@ private final MinecraftServer server; + private boolean silent; // Paper - silence feedback when API requests sprint - public ServerTickRateManager(MinecraftServer server) { + public ServerTickRateManager(final MinecraftServer server) { this.server = server; @@ -68,6 +_,13 @@ } - public boolean requestGameToSprint(int sprintTime) { + public boolean requestGameToSprint(final int time) { + // Paper start - silence feedback when API requests sprint -+ return requestGameToSprint(sprintTime, false); ++ return requestGameToSprint(time, false); + } + -+ public boolean requestGameToSprint(int sprintTime, boolean silent) { ++ public boolean requestGameToSprint(final int time, final boolean silent) { + if (!isSprinting()) this.silent = silent; + // Paper end - silence feedback when API requests sprint - boolean flag = this.remainingSprintTicks > 0L; + boolean interrupted = this.remainingSprintTicks > 0L; this.sprintTimeSpend = 0L; - this.scheduledCurrentSprintTicks = sprintTime; -@@ -84,7 +_,10 @@ - String string = String.format(Locale.ROOT, "%.2f", l == 0L ? this.millisecondsPerTick() : d / l); + this.scheduledCurrentSprintTicks = time; +@@ -86,9 +_,12 @@ + ); this.scheduledCurrentSprintTicks = 0L; this.sprintTimeSpend = 0L; -- this.server.createCommandSourceStack().sendSuccess(() -> Component.translatable("commands.tick.sprint.report", i, string), true); +- this.server + // Paper start - silence feedback when API requests sprint -+ if (!this.silent) this.server.createCommandSourceStack().sendSuccess(() -> Component.translatable("commands.tick.sprint.report", i, string), true); ++ if (!this.silent) this.server + .createCommandSourceStack() + .sendSuccess(() -> Component.translatable("commands.tick.sprint.report", ticksPerSecond, millisecondsPerTick), true); + this.silent = false; + // Paper end - silence feedback when API requests sprint this.remainingSprintTicks = 0L; diff --git a/paper-server/patches/sources/net/minecraft/server/Services.java.patch b/paper-server/patches/sources/net/minecraft/server/Services.java.patch index 7c8740bb9afa..7870efcfc8d8 100644 --- a/paper-server/patches/sources/net/minecraft/server/Services.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/Services.java.patch @@ -4,11 +4,11 @@ GameProfileRepository profileRepository, UserNameToIdResolver nameToIdCache, ProfileResolver profileResolver -+ , @javax.annotation.Nullable PaperServices paper // Paper ++ , @Nullable PaperServices paper // Paper ) { public static final String USERID_CACHE_FILE = "usercache.json"; -- public static Services create(YggdrasilAuthenticationService authenticationService, File profileRepository) { +- public static Services create(final YggdrasilAuthenticationService serviceAccess, final File nameCacheDir) { + // Paper start - add paper configuration files + public record PaperServices( + io.papermc.paper.configuration.PaperConfigurations configurations, @@ -25,23 +25,23 @@ + } + // Paper end - add paper configuration files + -+ public static Services create(YggdrasilAuthenticationService authenticationService, File profileRepository, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper - add optionset to load paper config files; add userCacheFile parameter - MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService(); - GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository(); -- UserNameToIdResolver userNameToIdResolver = new CachedUserNameToIdResolver(gameProfileRepository, new File(profileRepository, "usercache.json")); -- ProfileResolver profileResolver = new ProfileResolver.Cached(minecraftSessionService, userNameToIdResolver); -- return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, userNameToIdResolver, profileResolver); -+ UserNameToIdResolver userNameToIdResolver = new CachedUserNameToIdResolver(gameProfileRepository, userCacheFile); // Paper ++ public static Services create(final YggdrasilAuthenticationService serviceAccess, final File nameCacheDir, final File userCacheFile, final joptsimple.OptionSet options) throws Exception { // Paper - add options to load paper config files; add userCacheFile parameter + MinecraftSessionService sessionService = serviceAccess.createMinecraftSessionService(); + GameProfileRepository profileRepository = serviceAccess.createProfileRepository(); +- UserNameToIdResolver profileCache = new CachedUserNameToIdResolver(profileRepository, new File(nameCacheDir, "usercache.json")); +- ProfileResolver profileResolver = new ProfileResolver.Cached(sessionService, profileCache); +- return new Services(sessionService, serviceAccess.getServicesKeySet(), profileRepository, profileCache, profileResolver); ++ UserNameToIdResolver profileCache = new CachedUserNameToIdResolver(profileRepository, userCacheFile); // Paper + // Paper start - load paper config files from cli options -+ final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath(); -+ final java.nio.file.Path configDirPath = ((File) optionSet.valueOf("paper-settings-directory")).toPath(); -+ io.papermc.paper.configuration.PaperConfigurations paperConfigurations = io.papermc.paper.configuration.PaperConfigurations.setup(legacyConfigPath, configDirPath, profileRepository.toPath(), (File) optionSet.valueOf("spigot-settings")); ++ final java.nio.file.Path legacyConfigPath = ((File) options.valueOf("paper-settings")).toPath(); ++ final java.nio.file.Path configDirPath = ((File) options.valueOf("paper-settings-directory")).toPath(); ++ io.papermc.paper.configuration.PaperConfigurations paperConfigurations = io.papermc.paper.configuration.PaperConfigurations.setup(legacyConfigPath, configDirPath, nameCacheDir.toPath(), (File) options.valueOf("spigot-settings")); + PaperServices paperServices = new PaperServices( + paperConfigurations, + new io.papermc.paper.profile.PaperFilledProfileCache() + ); -+ ProfileResolver profileResolver = new ProfileResolver.Cached(minecraftSessionService, userNameToIdResolver, paperServices.filledProfileCache()); -+ return new Services(minecraftSessionService, authenticationService.getServicesKeySet(), gameProfileRepository, userNameToIdResolver, profileResolver, paperServices); ++ ProfileResolver profileResolver = new ProfileResolver.Cached(sessionService, profileCache, paperServices.filledProfileCache()); ++ return new Services(sessionService, serviceAccess.getServicesKeySet(), profileRepository, profileCache, profileResolver, paperServices); + // Paper end - load paper config files from cli options } diff --git a/paper-server/patches/sources/net/minecraft/server/WorldLoader.java.patch b/paper-server/patches/sources/net/minecraft/server/WorldLoader.java.patch index 58978e5e9ff9..d4cd12d70873 100644 --- a/paper-server/patches/sources/net/minecraft/server/WorldLoader.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/WorldLoader.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/WorldLoader.java +++ b/net/minecraft/server/WorldLoader.java -@@ -38,7 +_,7 @@ - CloseableResourceManager closeableResourceManager = pair.getSecond(); - LayeredRegistryAccess layeredRegistryAccess = RegistryLayer.createRegistryAccess(); - List> list = TagLoader.loadTagsForExistingRegistries( -- closeableResourceManager, layeredRegistryAccess.getLayer(RegistryLayer.STATIC) -+ closeableResourceManager, layeredRegistryAccess.getLayer(RegistryLayer.STATIC), io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL // Paper - tag lifecycle - add cause - ); - RegistryAccess.Frozen accessForLoading = layeredRegistryAccess.getAccessForLoading(RegistryLayer.WORLDGEN); - List> list1 = TagLoader.buildUpdatedLookups(accessForLoading, list); +@@ -35,7 +_,7 @@ + CloseableResourceManager resources = packsAndResourceManager.getSecond(); + LayeredRegistryAccess initialLayers = RegistryLayer.createRegistryAccess(); + List> staticLayerTags = TagLoader.loadTagsForExistingRegistries( +- resources, initialLayers.getLayer(RegistryLayer.STATIC) ++ resources, initialLayers.getLayer(RegistryLayer.STATIC), io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL // Paper - tag lifecycle - add cause + ); + RegistryAccess.Frozen worldgenLoadContext = initialLayers.getAccessForLoading(RegistryLayer.WORLDGEN); + List> worldgenContextRegistries = TagLoader.buildUpdatedLookups(worldgenLoadContext, staticLayerTags); diff --git a/paper-server/patches/sources/net/minecraft/server/bossevents/CustomBossEvent.java.patch b/paper-server/patches/sources/net/minecraft/server/bossevents/CustomBossEvent.java.patch index 511f66f064a7..df4b3371f51a 100644 --- a/paper-server/patches/sources/net/minecraft/server/bossevents/CustomBossEvent.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/bossevents/CustomBossEvent.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/bossevents/CustomBossEvent.java +++ b/net/minecraft/server/bossevents/CustomBossEvent.java -@@ -23,6 +_,16 @@ - private final Set players = Sets.newHashSet(); +@@ -24,6 +_,16 @@ private int value; private int max = 100; + private final Runnable dirtyCallback; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.boss.KeyedBossBar bossBar; ++ private org.bukkit.boss.@org.jspecify.annotations.Nullable KeyedBossBar bossBar; + + public org.bukkit.boss.KeyedBossBar getBukkitEntity() { + if (this.bossBar == null) { @@ -15,5 +15,5 @@ + } + // CraftBukkit end - public CustomBossEvent(Identifier id, Component name) { - super(name, BossEvent.BossBarColor.WHITE, BossEvent.BossBarOverlay.PROGRESS); + public CustomBossEvent(final UUID id, final Identifier customId, final Component name, final Runnable dirtyCallback) { + super(id, name, BossEvent.BossBarColor.WHITE, BossEvent.BossBarOverlay.PROGRESS); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch index 3a29620e927c..e1adcc14f76f 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/BanIpCommands.java +++ b/net/minecraft/server/commands/BanIpCommands.java -@@ -68,7 +_,7 @@ +@@ -62,7 +_,7 @@ } - for (ServerPlayer serverPlayer : playersWithAddress) { -- serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned")); -+ serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"), org.bukkit.event.player.PlayerKickEvent.Cause.IP_BANNED); // Paper - kick event cause + for (ServerPlayer player : players) { +- player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned")); ++ player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"), org.bukkit.event.player.PlayerKickEvent.Cause.IP_BANNED); // Paper - kick event cause } - return playersWithAddress.size(); + return players.size(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/BanPlayerCommands.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/BanPlayerCommands.java.patch index b5141c2f0765..f61d1e26a18b 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/BanPlayerCommands.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/BanPlayerCommands.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/BanPlayerCommands.java +++ b/net/minecraft/server/commands/BanPlayerCommands.java -@@ -57,7 +_,7 @@ - ); - ServerPlayer player = source.getServer().getPlayerList().getPlayer(nameAndId.id()); - if (player != null) { -- player.connection.disconnect(Component.translatable("multiplayer.disconnect.banned")); -+ player.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"), org.bukkit.event.player.PlayerKickEvent.Cause.BANNED); // Paper - kick event cause +@@ -47,7 +_,7 @@ + source.sendSuccess(() -> Component.translatable("commands.ban.success", Component.literal(player.name()), entry.getReasonMessage()), true); + ServerPlayer online = source.getServer().getPlayerList().getPlayer(player.id()); + if (online != null) { +- online.connection.disconnect(Component.translatable("multiplayer.disconnect.banned")); ++ online.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"), org.bukkit.event.player.PlayerKickEvent.Cause.BANNED); // Paper - kick event cause } } } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/DeOpCommands.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/DeOpCommands.java.patch index 3b45d545db0d..b3a5b42896d0 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/DeOpCommands.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/DeOpCommands.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/DeOpCommands.java +++ b/net/minecraft/server/commands/DeOpCommands.java -@@ -39,7 +_,7 @@ - if (playerList.isOp(nameAndId)) { - playerList.deop(nameAndId); - i++; +@@ -35,7 +_,7 @@ + if (list.isOp(player)) { + list.deop(player); + count++; - source.sendSuccess(() -> Component.translatable("commands.deop.success", players.iterator().next().name()), true); -+ source.sendSuccess(() -> Component.translatable("commands.deop.success", nameAndId.name()), true); // Paper - fixes MC-253721 ++ source.sendSuccess(() -> Component.translatable("commands.deop.success", player.name()), true); // Paper - fixes MC-253721 } } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch index 8a3de200eb96..c6335f8a1965 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/commands/DebugCommand.java +++ b/net/minecraft/server/commands/DebugCommand.java -@@ -263,6 +_,13 @@ +@@ -277,6 +_,13 @@ return true; } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch index bacdafe0105a..940dc6091475 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch @@ -2,11 +2,11 @@ +++ b/net/minecraft/server/commands/DifficultyCommand.java @@ -31,10 +_,10 @@ - public static int setDifficulty(CommandSourceStack source, Difficulty difficulty) throws CommandSyntaxException { + public static int setDifficulty(final CommandSourceStack source, final Difficulty difficulty) throws CommandSyntaxException { MinecraftServer server = source.getServer(); - if (server.getWorldData().getDifficulty() == difficulty) { + if (source.getLevel().getDifficulty() == difficulty) { // CraftBukkit - throw ERROR_ALREADY_DIFFICULT.create(difficulty.getKey()); + throw ERROR_ALREADY_SAME_DIFFICULTY.create(difficulty.getSerializedName()); } else { - server.setDifficulty(difficulty, true); + server.setDifficulty(source.getLevel(), difficulty, source, true); // Paper - per level difficulty; don't skip other difficulty-changing logic (fix upstream's fix); WorldDifficultyChangeEvent diff --git a/paper-server/patches/sources/net/minecraft/server/commands/EffectCommands.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/EffectCommands.java.patch index 23d1fde806cd..e82fad73ce0e 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/EffectCommands.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/EffectCommands.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/server/commands/EffectCommands.java +++ b/net/minecraft/server/commands/EffectCommands.java -@@ -182,7 +_,7 @@ - for (Entity entity : targets) { +@@ -178,7 +_,7 @@ + for (Entity entity : entities) { if (entity instanceof LivingEntity) { - MobEffectInstance mobEffectInstance = new MobEffectInstance(effect, i1, amplifier, false, showParticles); -- if (((LivingEntity)entity).addEffect(mobEffectInstance, source.getEntity())) { -+ if (((LivingEntity)entity).addEffect(mobEffectInstance, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit - i++; + MobEffectInstance instance = new MobEffectInstance(effectHolder, duration, amplifier, false, particles); +- if (((LivingEntity)entity).addEffect(instance, source.getEntity())) { ++ if (((LivingEntity)entity).addEffect(instance, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit + count++; } } -@@ -212,7 +_,7 @@ - int i = 0; +@@ -208,7 +_,7 @@ + int count = 0; - for (Entity entity : targets) { + for (Entity entity : entities) { - if (entity instanceof LivingEntity && ((LivingEntity)entity).removeAllEffects()) { + if (entity instanceof LivingEntity && ((LivingEntity)entity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit - i++; + count++; } } -@@ -237,7 +_,7 @@ - int i = 0; +@@ -233,7 +_,7 @@ + int count = 0; - for (Entity entity : targets) { -- if (entity instanceof LivingEntity && ((LivingEntity)entity).removeEffect(effect)) { -+ if (entity instanceof LivingEntity && ((LivingEntity)entity).removeEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit - i++; + for (Entity entity : entities) { +- if (entity instanceof LivingEntity && ((LivingEntity)entity).removeEffect(effectHolder)) { ++ if (entity instanceof LivingEntity && ((LivingEntity)entity).removeEffect(effectHolder, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit + count++; } } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch index 9ffa66f958ae..0af763405329 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/server/commands/GameModeCommand.java +++ b/net/minecraft/server/commands/GameModeCommand.java -@@ -69,9 +_,21 @@ +@@ -63,9 +_,21 @@ } - private static boolean setGameMode(CommandSourceStack source, ServerPlayer player, GameType gameMode) { -- if (player.setGameMode(gameMode)) { + private static boolean setGameMode(final CommandSourceStack source, final ServerPlayer player, final GameType type) { +- if (player.setGameMode(type)) { + // Paper start - Expand PlayerGameModeChangeEvent -+ return setGameMode(source, player, gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND); ++ return setGameMode(source, player, type, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND); + } + -+ public static boolean setGameMode(CommandSourceStack source, ServerPlayer player, GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause) { -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameMode, cause, null); ++ public static boolean setGameMode(final CommandSourceStack source, final ServerPlayer player, final GameType type, final org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause) { ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(type, cause, null); + if (event != null && !event.isCancelled()) { + // Paper end - Expand PlayerGameModeChangeEvent - logGamemodeChange(source, player, gameMode); + logGamemodeChange(source, player, type); return true; + // Paper start - Expand PlayerGameModeChangeEvent + } else if (event != null && event.cancelMessage() != null) { diff --git a/paper-server/patches/sources/net/minecraft/server/commands/GameRuleCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/GameRuleCommand.java.patch index c308208079fb..aadb635807bc 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/GameRuleCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/GameRuleCommand.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/server/commands/GameRuleCommand.java +++ b/net/minecraft/server/commands/GameRuleCommand.java -@@ -37,8 +_,7 @@ +@@ -34,8 +_,7 @@ - private static int setRule(CommandContext context, GameRule rule) { - CommandSourceStack commandSourceStack = context.getSource(); -- T argument = context.getArgument("value", rule.valueClass()); -- commandSourceStack.getLevel().getGameRules().set(rule, argument, context.getSource().getServer()); -+ T argument = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(rule, context.getArgument("value", rule.valueClass()), commandSourceStack.getLevel(), context.getSource().getBukkitSender()).value(); // Paper - per-world game rules and event - commandSourceStack.sendSuccess(() -> Component.translatable("commands.gamerule.set", rule.id(), rule.serialize(argument)), true); - return rule.getCommandResult(argument); + private static int setRule(final CommandContext context, final GameRule gameRule) { + CommandSourceStack source = context.getSource(); +- T value = context.getArgument("value", gameRule.valueClass()); +- source.getLevel().getGameRules().set(gameRule, value, context.getSource().getServer()); ++ T value = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(gameRule, context.getArgument("value", gameRule.valueClass()), source.getLevel(), source.getBukkitSender()).value(); // Paper - per-world game rules and event + source.sendSuccess(() -> Component.translatable("commands.gamerule.set", gameRule.id(), gameRule.serialize(value)), true); + return gameRule.getCommandResult(value); } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch index 8549e57e209f..341dc8af2e35 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/server/commands/GiveCommand.java +++ b/net/minecraft/server/commands/GiveCommand.java -@@ -69,7 +_,7 @@ - ItemStack itemStack1 = item.createItemStack(min, false); - boolean flag = serverPlayer.getInventory().add(itemStack1); - if (flag && itemStack1.isEmpty()) { -- ItemEntity itemEntity = serverPlayer.drop(itemStack, false); -+ ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command - if (itemEntity != null) { - itemEntity.makeFakeItem(); +@@ -62,7 +_,7 @@ + ItemStack copyToDrop = prototypeItemStack.copyWithCount(size); + boolean added = player.getInventory().add(copyToDrop); + if (added && copyToDrop.isEmpty()) { +- ItemEntity drop = player.drop(prototypeItemStack.copy(), false); ++ ItemEntity drop = player.drop(prototypeItemStack.copy(), false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command + if (drop != null) { + drop.makeFakeItem(); } -@@ -87,7 +_,7 @@ +@@ -80,7 +_,7 @@ ); - serverPlayer.containerMenu.broadcastChanges(); + player.containerMenu.broadcastChanges(); } else { -- ItemEntity itemEntity = serverPlayer.drop(itemStack1, false); -+ ItemEntity itemEntity = serverPlayer.drop(itemStack1, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command - if (itemEntity != null) { - itemEntity.setNoPickUpDelay(); - itemEntity.setTarget(serverPlayer.getUUID()); -@@ -102,7 +_,7 @@ - true +- ItemEntity drop = player.drop(copyToDrop, false); ++ ItemEntity drop = player.drop(copyToDrop, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command + if (drop != null) { + drop.setNoPickUpDelay(); + drop.setTarget(player.getUUID()); +@@ -98,7 +_,7 @@ ); } else { -- source.sendSuccess(() -> Component.translatable("commands.give.success.single", count, itemStack.getDisplayName(), targets.size()), true); -+ source.sendSuccess(() -> Component.translatable("commands.give.success.multiple", count, itemStack.getDisplayName(), targets.size()), true); // Paper - MC-151857 - correct translation key + source.sendSuccess( +- () -> Component.translatable("commands.give.success.single", count, prototypeItemStack.getDisplayName(), players.size()), true ++ () -> Component.translatable("commands.give.success.multiple", count, prototypeItemStack.getDisplayName(), players.size()), true // Paper - MC-151857 - correct translation key + ); } - return targets.size(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch index c40eb5ee9982..6427c3df646f 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/KickCommand.java +++ b/net/minecraft/server/commands/KickCommand.java -@@ -50,7 +_,7 @@ +@@ -42,7 +_,7 @@ - for (ServerPlayer serverPlayer : players) { - if (!source.getServer().isSingleplayerOwner(serverPlayer.nameAndId())) { -- serverPlayer.connection.disconnect(reason); -+ serverPlayer.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause - source.sendSuccess(() -> Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true); - i++; + for (ServerPlayer player : players) { + if (!source.getServer().isSingleplayerOwner(player.nameAndId())) { +- player.connection.disconnect(reason); ++ player.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause + source.sendSuccess(() -> Component.translatable("commands.kick.success", player.getDisplayName(), reason), true); + count++; } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/ListPlayersCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/ListPlayersCommand.java.patch index feda570539a2..bf0c37218963 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/ListPlayersCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/ListPlayersCommand.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/server/commands/ListPlayersCommand.java @@ -32,7 +_,14 @@ - private static int format(CommandSourceStack source, Function nameExtractor) { + private static int format(final CommandSourceStack source, final Function formatter) { PlayerList playerList = source.getServer().getPlayerList(); - List players = playerList.getPlayers(); + // CraftBukkit start @@ -13,6 +13,6 @@ + } + final List players = playersTemp; + // CraftBukkit end - Component component = ComponentUtils.formatList(players, nameExtractor); - source.sendSuccess(() -> Component.translatable("commands.list.players", players.size(), playerList.getMaxPlayers(), component), false); + Component listComponent = ComponentUtils.formatList(players, formatter); + source.sendSuccess(() -> Component.translatable("commands.list.players", players.size(), playerList.getMaxPlayers(), listComponent), false); return players.size(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/LocateCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/LocateCommand.java.patch index 697228612e87..eb5a1ba012fb 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/LocateCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/LocateCommand.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/server/commands/LocateCommand.java +++ b/net/minecraft/server/commands/LocateCommand.java -@@ -199,6 +_,6 @@ - private static float dist(int x1, int z1, int x2, int z2) { - int i = x2 - x1; - int i1 = z2 - z1; -- return Mth.sqrt(i * i + i1 * i1); -+ return (float) Math.hypot(i, i1); // Paper - Fix MC-177381 +@@ -191,6 +_,6 @@ + private static float dist(final int x1, final int z1, final int x2, final int z2) { + int dx = x2 - x1; + int dz = z2 - z1; +- return Mth.sqrt(dx * dx + dz * dz); ++ return (float) Math.hypot(dx, dz); // Paper - Fix MC-177381 } } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch index 2fd0cc8bcb2a..e8f8b0c9f58f 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/server/commands/PlaceCommand.java +++ b/net/minecraft/server/commands/PlaceCommand.java -@@ -302,6 +_,7 @@ - if (!structureStart.isValid()) { +@@ -298,6 +_,7 @@ + if (!start.isValid()) { throw ERROR_STRUCTURE_FAILED.create(); } else { -+ structureStart.generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.COMMAND; // CraftBukkit - set AsyncStructureGenerateEvent.Cause.COMMAND as generation cause - BoundingBox boundingBox = structureStart.getBoundingBox(); - ChunkPos chunkPos = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); - ChunkPos chunkPos1 = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); ++ start.generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.COMMAND; // CraftBukkit - set AsyncStructureGenerateEvent.Cause.COMMAND as generation cause + BoundingBox boundingBox = start.getBoundingBox(); + ChunkPos chunkMin = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos chunkMax = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/ReloadCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/ReloadCommand.java.patch index a96e3087c595..11a6896a3527 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/ReloadCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/ReloadCommand.java.patch @@ -3,24 +3,24 @@ @@ -16,7 +_,7 @@ private static final Logger LOGGER = LogUtils.getLogger(); - public static void reloadPacks(Collection selectedIds, CommandSourceStack source) { -- source.getServer().reloadResources(selectedIds).exceptionally(throwable -> { -+ source.getServer().reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent + public static void reloadPacks(final Collection selectedPacks, final CommandSourceStack source) { +- source.getServer().reloadResources(selectedPacks).exceptionally(throwable -> { ++ source.getServer().reloadResources(selectedPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent LOGGER.warn("Failed to execute reload", throwable); source.sendFailure(Component.translatable("commands.reload.failure")); return null; @@ -24,7 +_,7 @@ } - private static Collection discoverNewPacks(PackRepository packRepository, WorldData worldData, Collection selectedIds) { + private static Collection discoverNewPacks(final PackRepository packRepository, final WorldData worldData, final Collection currentPacks) { - packRepository.reload(); + packRepository.reload(true); // Paper - will perform a full reload - Collection list = Lists.newArrayList(selectedIds); + Collection selected = Lists.newArrayList(currentPacks); Collection disabled = worldData.getDataConfiguration().dataPacks().getDisabled(); @@ -36,6 +_,16 @@ - return list; + return selected; } + + // CraftBukkit start @@ -33,5 +33,5 @@ + } + // CraftBukkit end - public static void register(CommandDispatcher dispatcher) { - dispatcher.register(Commands.literal("reload").requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS)).executes(commandContext -> { + public static void register(final CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("reload").requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS)).executes(s -> { diff --git a/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch index 1a405cea646d..75ea71d04e42 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/RideCommand.java +++ b/net/minecraft/server/commands/RideCommand.java -@@ -60,7 +_,7 @@ - Entity vehicle1 = target.getVehicle(); - if (vehicle1 != null) { - throw ERROR_ALREADY_RIDING.create(target.getDisplayName(), vehicle1.getDisplayName()); -- } else if (vehicle.getType() == EntityType.PLAYER) { -+ } else if (vehicle.getType() == EntityType.PLAYER && !io.papermc.paper.configuration.GlobalConfiguration.get().commands.rideCommandAllowPlayerAsVehicle) { // Paper - allow player as vehicle +@@ -54,7 +_,7 @@ + Entity currentVehicle = target.getVehicle(); + if (currentVehicle != null) { + throw ERROR_ALREADY_RIDING.create(target.getDisplayName(), currentVehicle.getDisplayName()); +- } else if (vehicle.is(EntityType.PLAYER)) { ++ } else if (vehicle.is(EntityType.PLAYER) && !io.papermc.paper.configuration.GlobalConfiguration.get().commands.rideCommandAllowPlayerAsVehicle) { // Paper - allow player as vehicle throw ERROR_MOUNTING_PLAYER.create(); - } else if (target.getSelfAndPassengers().anyMatch(entity -> entity == vehicle)) { + } else if (target.getSelfAndPassengers().anyMatch(e -> e == vehicle)) { throw ERROR_MOUNTING_LOOP.create(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch index 1e8073d25ded..ea60bef179a9 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch @@ -3,27 +3,27 @@ @@ -32,7 +_,7 @@ ); private static final SimpleCommandExceptionType ERROR_MACRO = new SimpleCommandExceptionType(Component.translatableEscape("commands.schedule.macro")); - private static final SuggestionProvider SUGGEST_SCHEDULE = (context, builder) -> SharedSuggestionProvider.suggest( -- context.getSource().getServer().getWorldData().overworldData().getScheduledEvents().getEventsIds(), builder -+ context.getSource().getLevel().serverLevelData.getScheduledEvents().getEventsIds(), builder // Paper - Make schedule command per-world + private static final SuggestionProvider SUGGEST_SCHEDULE = (c, p) -> SharedSuggestionProvider.suggest( +- c.getSource().getServer().getScheduledEvents().getEventsIds(), p ++ c.getSource().getLevel().scheduledEvents.getEventsIds(), p // Paper - Make schedule command per-world ); - public static void register(CommandDispatcher dispatcher) { + public static void register(final CommandDispatcher dispatcher) { @@ -101,7 +_,7 @@ } else { - long l = source.getLevel().getGameTime() + time; - Identifier identifier = function.getFirst(); -- TimerQueue scheduledEvents = source.getServer().getWorldData().overworldData().getScheduledEvents(); -+ TimerQueue scheduledEvents = source.getLevel().serverLevelData.overworldData().getScheduledEvents(); // CraftBukkit - SPIGOT-6667: Use world specific function timer - Optional> optional = function.getSecond().left(); - if (optional.isPresent()) { - if (optional.get() instanceof MacroFunction) { -@@ -130,7 +_,7 @@ + long tickTime = source.getLevel().getGameTime() + time; + Identifier callbackId = callback.getFirst(); +- TimerQueue queue = source.getServer().getScheduledEvents(); ++ TimerQueue queue = source.getLevel().scheduledEvents; // CraftBukkit - SPIGOT-6667: Use world specific function timer + Optional> function = callback.getSecond().left(); + if (function.isPresent()) { + if (function.get() instanceof MacroFunction) { +@@ -132,7 +_,7 @@ } - private static int remove(CommandSourceStack source, String function) throws CommandSyntaxException { -- int i = source.getServer().getWorldData().overworldData().getScheduledEvents().remove(function); -+ int i = source.getLevel().serverLevelData.overworldData().getScheduledEvents().remove(function); // Paper - Make schedule command per-world - if (i == 0) { - throw ERROR_CANT_REMOVE.create(function); + private static int remove(final CommandSourceStack source, final String id) throws CommandSyntaxException { +- int count = source.getServer().getScheduledEvents().remove(id); ++ int count = source.getLevel().scheduledEvents.remove(id); // Paper - Make schedule command per-world + if (count == 0) { + throw ERROR_CANT_REMOVE.create(id); } else { diff --git a/paper-server/patches/sources/net/minecraft/server/commands/SetSpawnCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/SetSpawnCommand.java.patch index de35da33ce39..e8bae4a40d90 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/SetSpawnCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/SetSpawnCommand.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/server/commands/SetSpawnCommand.java +++ b/net/minecraft/server/commands/SetSpawnCommand.java -@@ -74,24 +_,34 @@ - float f = Mth.wrapDegrees(rotation.y); - float f1 = Mth.clamp(rotation.x, -90.0F, 90.0F); +@@ -74,12 +_,22 @@ + float yaw = Mth.wrapDegrees(rotationVector.y); + float pitch = Mth.clamp(rotationVector.x, -90.0F, 90.0F); + final Collection actualTargets = new java.util.ArrayList<>(); // Paper - Add PlayerSetSpawnEvent - for (ServerPlayer serverPlayer : targets) { -- serverPlayer.setRespawnPosition(new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(resourceKey, pos, f, f1), true), false); + for (ServerPlayer target : targets) { +- target.setRespawnPosition(new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(dimension, pos, yaw, pitch), true), false); - } + // Paper start - Add PlayerSetSpawnEvent -+ if (serverPlayer.setRespawnPosition(new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(resourceKey, pos, f, f1), true), false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { -+ actualTargets.add(serverPlayer); ++ if (target.setRespawnPosition(new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(dimension, pos, yaw, pitch), true), false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { ++ actualTargets.add(target); + } + // Paper end - Add PlayerSetSpawnEvent + } @@ -20,20 +20,28 @@ + } + // Paper end - Add PlayerSetSpawnEvent - String string = resourceKey.identifier().toString(); + String dimensionName = dimension.identifier().toString(); - if (targets.size() == 1) { + if (actualTargets.size() == 1) { // Paper - Add PlayerSetSpawnEvent source.sendSuccess( () -> Component.translatable( -- "commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), f, f1, string, targets.iterator().next().getDisplayName() -+ "commands.spawnpoint.success.single", pos.getX(), pos.getY(), pos.getZ(), f, f1, string, actualTargets.iterator().next().getDisplayName() // Paper - Add PlayerSetSpawnEvent + "commands.spawnpoint.success.single", +@@ -89,19 +_,19 @@ + yaw, + pitch, + dimensionName, +- targets.iterator().next().getDisplayName() ++ actualTargets.iterator().next().getDisplayName() // Paper - Add PlayerSetSpawnEvent ), true ); } else { source.sendSuccess( -- () -> Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), f, f1, string, targets.size()), true -+ () -> Component.translatable("commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), f, f1, string, actualTargets.size()), true // Paper - Add PlayerSetSpawnEvent + () -> Component.translatable( +- "commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), yaw, pitch, dimensionName, targets.size() ++ "commands.spawnpoint.success.multiple", pos.getX(), pos.getY(), pos.getZ(), yaw, pitch, dimensionName, actualTargets.size() // Paper - Add PlayerSetSpawnEvent + ), + true ); } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/SpreadPlayersCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/SpreadPlayersCommand.java.patch index a76793b0397b..a1efbaa43e20 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/SpreadPlayersCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/SpreadPlayersCommand.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/server/commands/SpreadPlayersCommand.java +++ b/net/minecraft/server/commands/SpreadPlayersCommand.java -@@ -255,6 +_,7 @@ +@@ -265,6 +_,7 @@ entity.getYRot(), entity.getXRot(), true + , org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND // CraftBukkit - handle teleport reason ); - double d1 = Double.MAX_VALUE; + double closest = Double.MAX_VALUE; diff --git a/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch index b55632f3d87a..3c6f91342b94 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/server/commands/SummonCommand.java +++ b/net/minecraft/server/commands/SummonCommand.java -@@ -80,7 +_,7 @@ +@@ -78,7 +_,7 @@ BlockPos blockPos = BlockPos.containing(pos); if (!Level.isInSpawnableBounds(blockPos)) { throw INVALID_POSITION.create(); - } else if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful()) { -+ } else if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful(tag)) { // Paper - check peaceful override ++ } else if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful(nbt)) { // Paper - check peaceful override throw ERROR_FAILED_PEACEFUL.create(); } else { - CompoundTag compoundTag = tag.copy(); -@@ -88,6 +_,7 @@ + CompoundTag entityTag = nbt.copy(); +@@ -86,6 +_,7 @@ ServerLevel level = source.getLevel(); - Entity entity = EntityType.loadEntityRecursive(compoundTag, level, EntitySpawnReason.COMMAND, entity1 -> { - entity1.snapTo(pos.x, pos.y, pos.z, entity1.getYRot(), entity1.getXRot()); -+ entity1.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason - return entity1; + Entity entity = EntityType.loadEntityRecursive(entityTag, level, EntitySpawnReason.COMMAND, e -> { + e.snapTo(pos.x, pos.y, pos.z, e.getYRot(), e.getXRot()); ++ e.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason + return e; }); if (entity == null) { -@@ -97,7 +_,7 @@ +@@ -95,7 +_,7 @@ mob.finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, null); } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch index 01aa8b939bc4..448fd552bf7f 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/TeleportCommand.java +++ b/net/minecraft/server/commands/TeleportCommand.java -@@ -263,7 +_,7 @@ - float f1 = relatives.contains(Relative.X_ROT) ? xRot - target.getXRot() : xRot; - float f2 = Mth.wrapDegrees(f); - float f3 = Mth.wrapDegrees(f1); -- if (target.teleportTo(level, d, d1, d2, relatives, f2, f3, true)) { -+ if (target.teleportTo(level, d, d1, d2, relatives, f2, f3, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND)) { // Paper - teleport cause +@@ -255,7 +_,7 @@ + float relativeOrAbsoluteXRot = relatives.contains(Relative.X_ROT) ? xRot - victim.getXRot() : xRot; + float newYRot = Mth.wrapDegrees(relativeOrAbsoluteYRot); + float newXRot = Mth.wrapDegrees(relativeOrAbsoluteXRot); +- if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true)) { ++ if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND)) { // Paper - teleport cause if (lookAt != null) { - lookAt.perform(source, target); + lookAt.perform(source, victim); } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch index efc275401c42..7dbcf005a8e7 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch @@ -1,37 +1,67 @@ --- a/net/minecraft/server/commands/TimeCommand.java +++ b/net/minecraft/server/commands/TimeCommand.java -@@ -56,8 +_,15 @@ +@@ -170,23 +_,61 @@ } - public static int setTime(CommandSourceStack source, int time) { -- for (ServerLevel serverLevel : source.getServer().getAllLevels()) { -- serverLevel.setDayTime(time); -+ for (ServerLevel serverLevel : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change -+ // serverLevel.setDayTime(time); -+ // CraftBukkit start -+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(serverLevel.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, time - serverLevel.getDayTime()); -+ org.bukkit.Bukkit.getPluginManager().callEvent(event); -+ if (!event.isCancelled()) { -+ serverLevel.setDayTime(serverLevel.getDayTime() + event.getSkipAmount()); + private static int setTotalTicks(final CommandSourceStack source, final Holder clock, final int totalTicks) { ++ // Paper start ++ // TODO - snapshot - 26.1 ++ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { ++ long currentTime = level.clockManager().getTotalTicks(clock); ++ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, totalTicks - currentTime); ++ if (event.callEvent()) { ++ level.clockManager().setTotalTicks(clock, currentTime + event.getSkipAmount()); + } -+ // CraftBukkit end - } - - source.getServer().forceTimeSynchronization(); -@@ -66,8 +_,14 @@ ++ } ++ // Paper end + ServerClockManager clockManager = source.getServer().clockManager(); +- clockManager.setTotalTicks(clock, totalTicks); ++ // clockManager.setTotalTicks(clock, totalTicks); + source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), totalTicks), true); + return totalTicks; } - public static int addTime(CommandSourceStack source, int amount) { -- for (ServerLevel serverLevel : source.getServer().getAllLevels()) { -- serverLevel.setDayTime(serverLevel.getDayTime() + amount); -+ for (ServerLevel serverLevel : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change -+ // CraftBukkit start -+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(serverLevel.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, amount); -+ org.bukkit.Bukkit.getPluginManager().callEvent(event); -+ if (!event.isCancelled()) { -+ serverLevel.setDayTime(serverLevel.getDayTime() + event.getSkipAmount()); + private static int addTime(final CommandSourceStack source, final Holder clock, final int time) { ++ // Paper start ++ // TODO - snapshot - 26.1 ++ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { ++ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, time);; ++ if (event.callEvent()) { ++ level.clockManager().addTicks(clock, event.getSkipAmount()); + } -+ // CraftBukkit end - } ++ } ++ // Paper end + ServerClockManager clockManager = source.getServer().clockManager(); +- clockManager.addTicks(clock, time); ++ // Paper - move up + long totalTicks = clockManager.getTotalTicks(clock); + source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), totalTicks), true); + return wrapTime(totalTicks); + } - source.getServer().forceTimeSynchronization(); + private static int setTimeToTimeMarker(final CommandSourceStack source, final Holder clock, final ResourceKey timeMarkerId) throws CommandSyntaxException { ++ // Paper start ++ // TODO - snapshot - 26.1 ++ boolean foundMarker = false; ++ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { ++ java.util.OptionalLong targetTime = level.clockManager().getTotalTicksToTimeMarker(clock, timeMarkerId); ++ if (targetTime.isEmpty()) { ++ continue; ++ } ++ ++ foundMarker = true; ++ long currentTime = level.clockManager().getTotalTicks(clock); ++ long delta = targetTime.getAsLong() - currentTime; ++ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, delta); ++ if (event.callEvent()) { ++ level.clockManager().setTotalTicks(clock, currentTime + event.getSkipAmount()); ++ } ++ } ++ // Paper end ++ + ServerClockManager clockManager = source.getServer().clockManager(); +- if (!clockManager.moveToTimeMarker(clock, timeMarkerId)) { ++ if (!foundMarker) { // Paper + throw ERROR_NO_TIME_MARKER_FOUND.create(clock.getRegisteredName(), timeMarkerId); + } else { + source.sendSuccess( diff --git a/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch index 17c29d6a3d34..a88eca96a9e1 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/WaypointCommand.java +++ b/net/minecraft/server/commands/WaypointCommand.java -@@ -166,7 +_,7 @@ +@@ -164,7 +_,7 @@ } - private static void mutateIcon(CommandSourceStack source, WaypointTransmitter waypoint, Consumer mutator) { + private static void mutateIcon(final CommandSourceStack source, final WaypointTransmitter waypoint, final Consumer iconConsumer) { - ServerLevel level = source.getLevel(); + ServerLevel level = (waypoint instanceof LivingEntity livingEntity) ? (net.minecraft.server.level.ServerLevel) livingEntity.level() : source.getLevel(); // Paper - MC-300685 use level of waypoint if it's a living entity for broadcast level.getWaypointManager().untrackWaypoint(waypoint); - mutator.accept(waypoint.waypointIcon()); + iconConsumer.accept(waypoint.waypointIcon()); level.getWaypointManager().trackWaypoint(waypoint); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/WeatherCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/WeatherCommand.java.patch index d5d445aa1e96..6907c2cc673c 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/WeatherCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/WeatherCommand.java.patch @@ -1,30 +1,25 @@ --- a/net/minecraft/server/commands/WeatherCommand.java +++ b/net/minecraft/server/commands/WeatherCommand.java -@@ -44,23 +_,23 @@ +@@ -48,19 +_,19 @@ } - private static int getDuration(CommandSourceStack source, int time, IntProvider timeProvider) { -- return time == -1 ? timeProvider.sample(source.getServer().overworld().getRandom()) : time; -+ return time == -1 ? timeProvider.sample(source.getLevel().getRandom()) : time; // CraftBukkit - SPIGOT-7680: per-world - } - - private static int setClear(CommandSourceStack source, int time) { -- source.getServer().overworld().setWeatherParameters(getDuration(source, time, ServerLevel.RAIN_DELAY), 0, false, false); -+ source.getLevel().setWeatherParameters(getDuration(source, time, ServerLevel.RAIN_DELAY), 0, false, false); // CraftBukkit - SPIGOT-7680: per-world + private static int setClear(final CommandSourceStack source, final int duration) { +- source.getServer().setWeatherParameters(getDuration(source, duration, ServerLevel.RAIN_DELAY), 0, false, false); ++ source.getServer().setWeatherParameters(source.getLevel(), getDuration(source, duration, ServerLevel.RAIN_DELAY), 0, false, false); // CraftBukkit - SPIGOT-7680: per-world source.sendSuccess(() -> Component.translatable("commands.weather.set.clear"), true); - return time; + return duration; } - private static int setRain(CommandSourceStack source, int time) { -- source.getServer().overworld().setWeatherParameters(0, getDuration(source, time, ServerLevel.RAIN_DURATION), true, false); -+ source.getLevel().setWeatherParameters(0, getDuration(source, time, ServerLevel.RAIN_DURATION), true, false); // CraftBukkit - SPIGOT-7680: per-world + private static int setRain(final CommandSourceStack source, final int duration) { +- source.getServer().setWeatherParameters(0, getDuration(source, duration, ServerLevel.RAIN_DURATION), true, false); ++ source.getServer().setWeatherParameters(source.getLevel(), 0, getDuration(source, duration, ServerLevel.RAIN_DURATION), true, false); // CraftBukkit - SPIGOT-7680: per-world source.sendSuccess(() -> Component.translatable("commands.weather.set.rain"), true); - return time; + return duration; } - private static int setThunder(CommandSourceStack source, int time) { -- source.getServer().overworld().setWeatherParameters(0, getDuration(source, time, ServerLevel.THUNDER_DURATION), true, true); -+ source.getLevel().setWeatherParameters(0, getDuration(source, time, ServerLevel.THUNDER_DURATION), true, true); // CraftBukkit - SPIGOT-7680: per-world + private static int setThunder(final CommandSourceStack source, final int duration) { +- source.getServer().setWeatherParameters(0, getDuration(source, duration, ServerLevel.THUNDER_DURATION), true, true); ++ source.getServer().setWeatherParameters(source.getLevel(), 0, getDuration(source, duration, ServerLevel.THUNDER_DURATION), true, true); // CraftBukkit - SPIGOT-7680: per-world source.sendSuccess(() -> Component.translatable("commands.weather.set.thunder"), true); - return time; + return duration; } diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch index e1901d0e5a8b..bf82e77c240c 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/server/dedicated/DedicatedPlayerList.java +++ b/net/minecraft/server/dedicated/DedicatedPlayerList.java @@ -16,6 +_,11 @@ - super(server, registries, playerIo, server.notificationManager()); + super(server, registries, playerDataStorage, server.notificationManager()); this.setViewDistance(server.viewDistance()); this.setSimulationDistance(server.simulationDistance()); + // Paper start - fix converting txt to json file; moved from constructor diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index c8cd84714454..c19fea33bc86 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -80,9 +_,9 @@ - static final Logger LOGGER = LogUtils.getLogger(); +@@ -84,9 +_,9 @@ + private static final Logger LOGGER = LogUtils.getLogger(); private static final int CONVERSION_RETRY_DELAY_MS = 5000; private static final int CONVERSION_RETRIES = 2; - private final List consoleInput = Collections.synchronizedList(Lists.newArrayList()); @@ -12,20 +12,25 @@ private @Nullable RconThread rconThread; public DedicatedServerSettings settings; private @Nullable MinecraftServerGui gui; -@@ -95,6 +_,7 @@ +@@ -99,6 +_,7 @@ private long lastHeartbeat; public DedicatedServer( + joptsimple.OptionSet options, net.minecraft.server.WorldLoader.DataLoadContext worldLoader, // CraftBukkit - Signature changed - Thread serverThread, - LevelStorageSource.LevelStorageAccess storageSource, - PackRepository packRepository, -@@ -103,9 +_,10 @@ - DataFixer fixerUpper, - Services services + final Thread serverThread, + final LevelStorageSource.LevelStorageAccess levelStorageSource, + final PackRepository packRepository, +@@ -109,6 +_,7 @@ + final Services services ) { -- super(serverThread, storageSource, packRepository, worldStem, Proxy.NO_PROXY, fixerUpper, services, LoggingLevelLoadListener.forDedicatedServer()); -+ super(options, worldLoader, serverThread, storageSource, packRepository, worldStem, Proxy.NO_PROXY, fixerUpper, services, LoggingLevelLoadListener.forDedicatedServer()); // CraftBukkit - Signature changed + super( ++ options, worldLoader, // CraftBukkit - Signature changed + serverThread, + levelStorageSource, + packRepository, +@@ -121,7 +_,8 @@ + true + ); this.settings = settings; - this.rconConsoleSource = new RconConsoleSource(this); + this.setMotd(settings.getProperties().motd.get()); // Paper - set field from initial properties @@ -33,23 +38,22 @@ this.serverTextFilter = ServerTextFilter.createFromConfig(settings.getProperties()); this.serverLinks = createServerLinks(settings); if (settings.getProperties().codeOfConduct) { -@@ -191,6 +_,10 @@ - Thread thread = new Thread("Server console handler") { +@@ -211,6 +_,10 @@ + @Override public void run() { + if (!org.bukkit.craftbukkit.Main.useConsole) return; // CraftBukkit + // Paper start - Use TerminalConsoleAppender + new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start(); + /* - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); - String string4; -@@ -200,17 +_,41 @@ - } + String line; +@@ -221,16 +_,41 @@ } catch (IOException var4) { DedicatedServer.LOGGER.error("Exception handling console input", (Throwable)var4); -- } -+ }*/ + } ++ */ + // Paper end - Use TerminalConsoleAppender } }; @@ -66,10 +70,10 @@ + System.setOut(org.apache.logging.log4j.io.IoBuilder.forLogger(logger).setLevel(org.apache.logging.log4j.Level.INFO).buildPrintStream()); + System.setErr(org.apache.logging.log4j.io.IoBuilder.forLogger(logger).setLevel(org.apache.logging.log4j.Level.WARN).buildPrintStream()); + // CraftBukkit end - thread.setDaemon(true); - thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); -- thread.start(); -+ // thread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down + consoleThread.setDaemon(true); + consoleThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); +- consoleThread.start(); ++ // consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().name()); if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); @@ -88,7 +92,7 @@ LOGGER.info("Loading properties"); DedicatedServerProperties properties = this.settings.getProperties(); if (this.isSingleplayer()) { -@@ -221,8 +_,46 @@ +@@ -241,8 +_,45 @@ this.setLocalIp(properties.serverIp); } @@ -98,7 +102,6 @@ + org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings")); + org.spigotmc.SpigotConfig.registerCommands(); + // Spigot end -+ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. + // Paper start - initialize global and world-defaults configuration + this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); + this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); @@ -111,7 +114,7 @@ + this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames + // Paper end - fix converting txt to json file + org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread -+ thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized ++ consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized + io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command + this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark + com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics @@ -133,14 +136,14 @@ + } + bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getLocalIp().substring("unix:".length())); + } else { - InetAddress inetAddress = null; + InetAddress localAddress = null; if (!this.getLocalIp().isEmpty()) { - inetAddress = InetAddress.getByName(this.getLocalIp()); -@@ -231,46 +_,72 @@ + localAddress = InetAddress.getByName(this.getLocalIp()); +@@ -251,46 +_,72 @@ if (this.getPort() < 0) { this.setPort(properties.serverPort); } -+ bindAddress = new java.net.InetSocketAddress(inetAddress, this.getPort()); ++ bindAddress = new java.net.InetSocketAddress(localAddress, this.getPort()); + } + // Paper end - Unix domain socket support @@ -148,7 +151,7 @@ LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); try { -- this.getConnection().startTcpServerListener(inetAddress, this.getPort()); +- this.getConnection().startTcpServerListener(localAddress, this.getPort()); + this.getConnection().startTcpServerListener(bindAddress); // Paper - Unix domain socket support } catch (IOException var11) { LOGGER.warn("**** FAILED TO BIND TO PORT!"); @@ -195,38 +198,38 @@ + */ + // CraftBukkit end - if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { + if (!OldUsersConverter.areOldUserlistsRemoved()) { return false; } else { - this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); + // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSubscribers(), RemoteDebugSampleType.TICK_TIME); - long nanos = Util.getNanos(); + long levelNanoTime = Util.getNanos(); this.services.nameToIdCache().resolveOfflineUsers(!this.usesAuthentication()); LOGGER.info("Preparing level \"{}\"", this.getLevelIdName()); - this.loadLevel(); + this.loadLevel(this.storageSource.getLevelId()); // CraftBukkit - long l = Util.getNanos() - nanos; - String string3 = String.format(Locale.ROOT, "%.3fs", l / 1.0E9); -- LOGGER.info("Done ({})! For help, type \"help\"", string3); -+ LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), string3); // Paper - Improve startup message, add total time + long elapsed = Util.getNanos() - levelNanoTime; + String time = String.format(Locale.ROOT, "%.3fs", elapsed / 1.0E9); +- LOGGER.info("Done ({})! For help, type \"help\"", time); ++ LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), time); // Paper - Improve startup message, add total time + this.initPostWorld(); // Paper - don't include plugins in world preparation time if (properties.announcePlayerAchievements != null) { -- this.worldData.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this); -+ this.worldData.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this.overworld()); // Paper - per-world game rules +- this.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this); ++ this.getAllLevels().forEach(l -> l.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this.overworld())); // Paper - per-world game rules } if (properties.enableQuery) { -@@ -283,7 +_,7 @@ +@@ -303,7 +_,7 @@ this.rconThread = RconThread.create(this); } - if (this.getMaxTickLength() > 0L) { + if (false && this.getMaxTickLength() > 0L) { // Spigot - disable - Thread thread1 = new Thread(new ServerWatchdog(this)); - thread1.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)); - thread1.setName("Server Watchdog"); -@@ -301,6 +_,12 @@ + Thread watchdog = new Thread(new ServerWatchdog(this)); + watchdog.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)); + watchdog.setName("Server Watchdog"); +@@ -322,6 +_,12 @@ } } @@ -239,24 +242,24 @@ @Override public boolean isEnforceWhitelist() { return this.settings.getProperties().enforceWhitelist.get(); -@@ -318,6 +_,7 @@ +@@ -339,6 +_,7 @@ @Override - public void setUsingWhitelist(boolean usingWhitelist) { + public void setUsingWhitelist(final boolean usingWhitelist) { + new com.destroystokyo.paper.event.server.WhitelistToggleEvent(usingWhitelist).callEvent(); // Paper - WhitelistToggleEvent - this.settings.update(dedicatedServerProperties -> dedicatedServerProperties.whiteList.update(this.registryAccess(), usingWhitelist)); + this.settings.update(p -> p.whiteList.update(this.registryAccess(), usingWhitelist)); } -@@ -368,7 +_,7 @@ +@@ -400,7 +_,7 @@ @Override - public void forceDifficulty() { + protected void forceDifficulty() { - this.setDifficulty(this.getProperties().difficulty.get(), true); + // this.setDifficulty(this.getProperties().difficulty.get(), true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current } public int viewDistance() { -@@ -424,11 +_,11 @@ +@@ -456,11 +_,11 @@ } if (this.rconThread != null) { @@ -270,7 +273,7 @@ } if (this.jsonRpcServer != null) { -@@ -438,6 +_,9 @@ +@@ -470,6 +_,9 @@ LOGGER.error("Interrupted while stopping the management server", (Throwable)var2); } } @@ -280,31 +283,31 @@ } @Override -@@ -447,12 +_,20 @@ +@@ -479,12 +_,20 @@ } - public void handleConsoleInput(String msg, CommandSourceStack source) { + public void handleConsoleInput(final String msg, final CommandSourceStack source) { - this.consoleInput.add(new ConsoleInput(msg, source)); + this.serverCommandQueue.add(new ConsoleInput(msg, source)); // Paper - Perf: use proper queue } public void handleConsoleInputs() { - while (!this.consoleInput.isEmpty()) { -- ConsoleInput consoleInput = this.consoleInput.remove(0); +- ConsoleInput input = this.consoleInput.remove(0); + // Paper start - Perf: use proper queue -+ ConsoleInput consoleInput; -+ while ((consoleInput = this.serverCommandQueue.poll()) != null) { ++ ConsoleInput input; ++ while ((input = this.serverCommandQueue.poll()) != null) { + // Paper end - Perf: use proper queue + // CraftBukkit start - ServerCommand for preprocessing -+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, consoleInput.msg); ++ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, input.msg); + this.server.getPluginManager().callEvent(event); + if (event.isCancelled()) continue; -+ consoleInput = new ConsoleInput(event.getCommand(), consoleInput.source); ++ input = new ConsoleInput(event.getCommand(), input.source); + // CraftBukkit end - this.getCommands().performPrefixedCommand(consoleInput.source, consoleInput.msg); + this.getCommands().performPrefixedCommand(input.source, input.msg); } } -@@ -592,12 +_,15 @@ +@@ -624,12 +_,15 @@ @Override public String getMotd() { @@ -313,16 +316,16 @@ } @Override - public void setMotd(String motd) { -- this.settings.update(dedicatedServerProperties -> dedicatedServerProperties.motd.update(this.registryAccess(), motd)); + public void setMotd(final String motd) { +- this.settings.update(p -> p.motd.update(this.registryAccess(), motd)); + // Paper start + super.setMotd(motd); -+ this.settings.update(dedicatedServerProperties -> dedicatedServerProperties.motd.update(this.registryAccess(), this.getMotd())); ++ this.settings.update(p -> p.motd.update(this.registryAccess(), this.getMotd())); + // Paper end } @Override -@@ -623,7 +_,11 @@ +@@ -655,7 +_,11 @@ @Override public boolean enforceSecureProfile() { DedicatedServerProperties properties = this.getProperties(); @@ -335,7 +338,7 @@ } @Override -@@ -708,21 +_,60 @@ +@@ -740,21 +_,60 @@ @Override public String getPluginNames() { @@ -367,7 +370,7 @@ } @Override - public String runCommand(String command) { + public String runCommand(final String command) { - this.rconConsoleSource.prepareForCommand(); - this.executeBlocking(() -> this.getCommands().performPrefixedCommand(this.rconConsoleSource.createCommandSourceStack(), command)); - return this.rconConsoleSource.getCommandResponse(); @@ -375,13 +378,13 @@ + throw new UnsupportedOperationException("Not supported - remote source required."); + } + -+ public String runCommand(RconConsoleSource rconConsoleSource, String s) { -+ if (s.isBlank()) return ""; // Paper - Do not process empty rcon commands ++ public String runCommand(final RconConsoleSource rconConsoleSource, final String command) { ++ if (command.isBlank()) return ""; // Paper - Do not process empty rcon commands + + rconConsoleSource.prepareForCommand(); + this.executeBlocking(() -> { + CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack(); -+ org.bukkit.event.server.RemoteServerCommandEvent event = new org.bukkit.event.server.RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); ++ org.bukkit.event.server.RemoteServerCommandEvent event = new org.bukkit.event.server.RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), command); + this.server.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; @@ -393,7 +396,7 @@ } @Override - public void stopServer() { + protected void stopServer() { this.notificationManager().serverShuttingDown(); super.stopServer(); - Util.shutdownExecutors(); @@ -401,7 +404,7 @@ } @Override -@@ -853,4 +_,15 @@ +@@ -882,4 +_,15 @@ public Map getCodeOfConducts() { return this.codeOfConductTexts; } diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch index 4525693454fd..098f8b33594e 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/server/dedicated/DedicatedServerProperties.java +++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java @@ -50,6 +_,7 @@ - static final Logger LOGGER = LogUtils.getLogger(); + private static final Logger LOGGER = LogUtils.getLogger(); private static final Pattern SHA1 = Pattern.compile("^[a-fA-F0-9]{40}$"); private static final Splitter COMMA_SPLITTER = Splitter.on(',').trimResults(); + public final boolean debug = this.get("debug", false); // CraftBukkit @@ -11,7 +11,7 @@ @@ -106,7 +_,7 @@ public final boolean broadcastRconToOps = this.get("broadcast-rcon-to-ops", true); public final boolean broadcastConsoleToOps = this.get("broadcast-console-to-ops", true); - public final int maxWorldSize = this.get("max-world-size", property -> Mth.clamp(property, 1, 29999984), 29999984); + public final int maxWorldSize = this.get("max-world-size", v -> Mth.clamp(v, 1, 29999984), 29999984); - public final boolean syncChunkWrites = this.get("sync-chunk-writes", true); + public final boolean syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag public final String regionFileComression = this.get("region-file-compression", "deflate"); @@ -25,19 +25,19 @@ + public Settings.MutableValue pauseWhenEmptySeconds = this.getMutable("pause-when-empty-seconds", -1); // Paper - disable tick sleeping by default private final DedicatedServerProperties.WorldDimensionData worldDimensionData; public final WorldOptions worldOptions; - public Settings.MutableValue acceptsTransfers = this.getMutable("accepts-transfers", false); + public final Settings.MutableValue acceptsTransfers = this.getMutable("accepts-transfers", false); + public final String rconIp; // Paper - Configurable rcon ip -- public DedicatedServerProperties(Properties properties) { -- super(properties); +- public DedicatedServerProperties(final Properties settings) { +- super(settings); + // CraftBukkit start -+ public DedicatedServerProperties(Properties properties, joptsimple.OptionSet optionset) { -+ super(properties, optionset); ++ public DedicatedServerProperties(final Properties settings, final joptsimple.OptionSet options) { ++ super(settings, options); + // CraftBukkit end - String string = this.get("level-seed", ""); - boolean flag = this.get("generate-structures", true); - long l = WorldOptions.parseSeed(string).orElse(WorldOptions.randomSeed()); -@@ -150,15 +_,21 @@ + String levelSeed = this.get("level-seed", ""); + boolean generateStructures = this.get("generate-structures", true); + long seed = WorldOptions.parseSeed(levelSeed).orElse(WorldOptions.randomSeed()); +@@ -150,15 +_,23 @@ this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled())) ); @@ -47,19 +47,21 @@ + // Paper end - Configurable rcon ip } -- public static DedicatedServerProperties fromFile(Path path) { -- return new DedicatedServerProperties(loadFromFile(path)); +- public static DedicatedServerProperties fromFile(final Path file) { +- return new DedicatedServerProperties(loadFromFile(file)); + // CraftBukkit start -+ public static DedicatedServerProperties fromFile(Path path, joptsimple.OptionSet optionset) { -+ return new DedicatedServerProperties(loadFromFile(path), optionset); ++ public static DedicatedServerProperties fromFile(final Path file, final joptsimple.OptionSet options) { ++ return new DedicatedServerProperties(loadFromFile(file), options); ++ // CraftBukkit end } @Override -- protected DedicatedServerProperties reload(RegistryAccess registryAccess, Properties properties) { +- protected DedicatedServerProperties reload(final RegistryAccess registryAccess, final Properties properties) { - return new DedicatedServerProperties(properties); -+ public DedicatedServerProperties reload(RegistryAccess registryAccess, Properties properties, joptsimple.OptionSet options) { ++ // CraftBukkit start ++ public DedicatedServerProperties reload(final RegistryAccess registryAccess, final Properties properties, final joptsimple.OptionSet options) { + return new DedicatedServerProperties(properties, options); + // CraftBukkit end } - private static @Nullable Component parseResourcePackPrompt(String json) { + private static @Nullable Component parseResourcePackPrompt(final String prompt) { diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch index acd4a0443e1b..659d08bc0172 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch @@ -4,13 +4,13 @@ private final Path source; private DedicatedServerProperties properties; -- public DedicatedServerSettings(Path source) { +- public DedicatedServerSettings(final Path source) { - this.source = source; - this.properties = DedicatedServerProperties.fromFile(source); + // CraftBukkit start -+ public DedicatedServerSettings(joptsimple.OptionSet optionset) { -+ this.source = ((java.io.File) optionset.valueOf("config")).toPath(); -+ this.properties = DedicatedServerProperties.fromFile(this.source, optionset); ++ public DedicatedServerSettings(joptsimple.OptionSet options) { ++ this.source = ((java.io.File) options.valueOf("config")).toPath(); ++ this.properties = DedicatedServerProperties.fromFile(this.source, options); + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch new file mode 100644 index 000000000000..d0a306f98961 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/server/dedicated/ServerWatchdog.java ++++ b/net/minecraft/server/dedicated/ServerWatchdog.java +@@ -49,7 +_,7 @@ + CrashReport report = createWatchdogCrashReport("Watching Server", this.server.getRunningThread().threadId()); + this.server.fillSystemReport(report.getSystemReport()); + CrashReportCategory serverStats = report.addCategory("Performance stats"); +- serverStats.setDetail("Random tick rate", () -> this.server.getGameRules().getAsString(GameRules.RANDOM_TICK_SPEED)); ++ serverStats.setDetail("Overworld random tick rate", () -> this.server.overworld().getGameRules().getAsString(GameRules.RANDOM_TICK_SPEED)); // Paper - per-level GameRules + serverStats.setDetail( + "Level stats", + () -> Streams.stream(this.server.getAllLevels()) diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch index f09c795ed4d6..9b7f098a142d 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch @@ -8,13 +8,13 @@ + // CraftBukkit start + private joptsimple.OptionSet options = null; -- public Settings(Properties properties) { -+ public Settings(Properties properties, final joptsimple.OptionSet options) { +- public Settings(final Properties properties) { ++ public Settings(final Properties properties, final joptsimple.OptionSet options) { this.properties = properties; + this.options = options; + } + -+ private String getOverride(String name, String value) { ++ private String getOverride(final String name, final String value) { + if (this.options != null && this.options.has(name)) { + return String.valueOf(this.options.valueOf(name)); + } @@ -23,36 +23,36 @@ + // CraftBukkit end } - public static Properties loadFromFile(Path filePath) { -+ if (!Files.exists(filePath)) return new Properties(); // CraftBukkit - SPIGOT-7465, MC-264979: Don't load if file doesn't exist + public static Properties loadFromFile(final Path file) { ++ if (!Files.exists(file)) return new Properties(); // CraftBukkit - SPIGOT-7465, MC-264979: Don't load if file doesn't exist try { try { Properties var13; @@ -65,7 +_,53 @@ } - public void store(Path filePath) { -- try (Writer bufferedWriter = Files.newBufferedWriter(filePath, StandardCharsets.UTF_8)) { -+ try /*(Writer bufferedWriter = Files.newBufferedWriter(filePath, StandardCharsets.UTF_8))*/ { // Paper + public void store(final Path output) { +- try (Writer os = Files.newBufferedWriter(output, StandardCharsets.UTF_8)) { ++ try /*(Writer os = Files.newBufferedWriter(output, StandardCharsets.UTF_8))*/ { // Paper + // CraftBukkit start - Don't attempt writing to file if it's read only -+ if (filePath.toFile().exists() && !filePath.toFile().canWrite()) { -+ Settings.LOGGER.warn("Can not write to file {}, skipping.", filePath); // Paper - log message file is read-only ++ if (output.toFile().exists() && !output.toFile().canWrite()) { ++ Settings.LOGGER.warn("Can not write to file {}, skipping.", output); // Paper - log message file is read-only + return; + } + // CraftBukkit end + // Paper start - allow skipping server.properties comments -+ java.io.OutputStream outputstream = Files.newOutputStream(filePath); ++ java.io.OutputStream outputstream = Files.newOutputStream(output); + java.io.BufferedOutputStream bufferedOutputStream = !skipComments ? new java.io.BufferedOutputStream(outputstream) : new java.io.BufferedOutputStream(outputstream) { + private boolean isRightAfterNewline = true; // If last written char was newline + private boolean isComment = false; // Are we writing comment currently? + + @Override -+ public void write(@org.jetbrains.annotations.NotNull byte[] b) throws IOException { ++ public void write(byte[] b) throws IOException { + this.write(b, 0, b.length); + } + + @Override -+ public void write(@org.jetbrains.annotations.NotNull byte[] bbuf, int off, int len) throws IOException { ++ public void write(byte[] bbuf, int off, int len) throws IOException { + int latest_offset = off; // The latest offset, updated when comment ends + for (int index = off; index < off + len; ++index ) { + byte c = bbuf[index]; @@ -78,51 +78,52 @@ + } + } + }; -+ java.io.BufferedWriter bufferedWriter = new java.io.BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); ++ java.io.BufferedWriter os = new java.io.BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); + // Paper end - allow skipping server.properties comments - this.properties.store(bufferedWriter, "Minecraft server properties"); + this.properties.store(os, "Minecraft server properties"); } catch (IOException var7) { - LOGGER.error("Failed to store properties to file: {}", filePath); -@@ -93,7 +_,7 @@ + LOGGER.error("Failed to store properties to file: {}", output); +@@ -95,7 +_,7 @@ } - public @Nullable String getStringRaw(String key) { + public @Nullable String getStringRaw(final String key) { - return (String)this.properties.get(key); + return (String)this.getOverride(key, this.properties.getProperty(key)); // CraftBukkit } - protected @Nullable V getLegacy(String key, Function serializer) { -@@ -107,6 +_,15 @@ + protected @Nullable V getLegacy(final String key, final Function deserializer) { +@@ -109,6 +_,16 @@ } - protected V get(String key, Function serializer, Function deserializer, V defaultValue) { + protected V get(final String key, final Function deserializer, final Function serializer, final V defaultValue) { + // CraftBukkit start + try { -+ return this.get0(key, serializer, deserializer, defaultValue); ++ return this.get0(key, deserializer, serializer, defaultValue); + } catch (Exception ex) { + throw new RuntimeException("Could not load invalidly configured property '" + key + "'", ex); + } + } -+ private V get0(String key, Function serializer, Function deserializer, V defaultValue) { ++ ++ private V get0(final String key, final Function deserializer, final Function serializer, final V defaultValue) { + // CraftBukkit end - String stringRaw = this.getStringRaw(key); - V object = MoreObjects.firstNonNull(stringRaw != null ? serializer.apply(stringRaw) : null, defaultValue); - this.properties.put(key, deserializer.apply(object)); -@@ -181,7 +_,7 @@ - return map; + String value = this.getStringRaw(key); + V result = MoreObjects.firstNonNull(value != null ? deserializer.apply(value) : null, defaultValue); + this.properties.put(key, serializer.apply(result)); +@@ -191,7 +_,7 @@ + return result; } -- protected abstract T reload(RegistryAccess registryAccess, Properties properties); -+ protected abstract T reload(RegistryAccess registryAccess, Properties properties, joptsimple.OptionSet optionset); // CraftBukkit +- protected abstract T reload(final RegistryAccess registryAccess, final Properties properties); ++ protected abstract T reload(final RegistryAccess registryAccess, final Properties properties, final joptsimple.OptionSet options); // CraftBukkit public class MutableValue implements Supplier { private final String key; -@@ -202,7 +_,7 @@ - public T update(RegistryAccess registryAccess, V newValue) { - Properties map = Settings.this.cloneProperties(); - map.put(this.key, this.serializer.apply(newValue)); -- return Settings.this.reload(registryAccess, map); -+ return Settings.this.reload(registryAccess, map, Settings.this.options); // CraftBukkit +@@ -214,7 +_,7 @@ + public T update(final RegistryAccess registryAccess, final V value) { + Properties properties = Settings.this.cloneProperties(); + properties.put(this.key, this.serializer.apply(value)); +- return Settings.this.reload(registryAccess, properties); ++ return Settings.this.reload(registryAccess, properties, Settings.this.options); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/server/dialog/body/ItemBody.java.patch b/paper-server/patches/sources/net/minecraft/server/dialog/body/ItemBody.java.patch index d541a55a099d..5e4dba13f2bf 100644 --- a/paper-server/patches/sources/net/minecraft/server/dialog/body/ItemBody.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dialog/body/ItemBody.java.patch @@ -9,5 +9,5 @@ + ExtraCodecs.intRange(1, 256).optionalFieldOf("width", 16).forGetter(ItemBody::width), // Paper - diff on change - update builder defaults/limits + ExtraCodecs.intRange(1, 256).optionalFieldOf("height", 16).forGetter(ItemBody::height) // Paper - diff on change - update builder defaults/limits ) - .apply(instance, ItemBody::new) + .apply(i, ItemBody::new) ); diff --git a/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch b/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch index d78cde0d2c0c..53a34b4876cc 100644 --- a/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/server/gui/MinecraftServerGui.java +++ b/net/minecraft/server/gui/MinecraftServerGui.java -@@ -53,6 +_,13 @@ - jFrame.pack(); - jFrame.setLocationRelativeTo(null); - jFrame.setVisible(true); +@@ -54,6 +_,13 @@ + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + // Paper start - Improve ServerGUI -+ jFrame.setName("Minecraft server"); ++ frame.setName("Minecraft server"); + try { -+ jFrame.setIconImage(javax.imageio.ImageIO.read(java.util.Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); ++ frame.setIconImage(javax.imageio.ImageIO.read(java.util.Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); + } catch (java.io.IOException ignore) { + } + // Paper end - Improve ServerGUI - jFrame.addWindowListener(new WindowAdapter() { + frame.addWindowListener(new WindowAdapter() { @Override - public void windowClosing(WindowEvent event) { -@@ -74,6 +_,7 @@ + public void windowClosing(final WindowEvent event) { +@@ -75,6 +_,7 @@ this.setLayout(new BorderLayout()); try { @@ -22,24 +22,24 @@ this.add(this.buildChatPanel(), "Center"); this.add(this.buildInfoPanel(), "West"); } catch (Exception var3) { -@@ -87,7 +_,7 @@ +@@ -88,7 +_,7 @@ private JComponent buildInfoPanel() { - JPanel jPanel = new JPanel(new BorderLayout()); -- StatsComponent statsComponent = new StatsComponent(this.server); -+ com.destroystokyo.paper.gui.GuiStatsComponent statsComponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier - this.finalizers.add(statsComponent::close); - jPanel.add(statsComponent, "North"); - jPanel.add(this.buildPlayerPanel(), "Center"); -@@ -150,6 +_,7 @@ + JPanel panel = new JPanel(new BorderLayout()); +- StatsComponent comp = new StatsComponent(this.server); ++ com.destroystokyo.paper.gui.GuiStatsComponent comp = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper - Make GUI graph fancier + this.finalizers.add(comp::close); + panel.add(comp, "North"); + panel.add(this.buildPlayerPanel(), "Center"); +@@ -155,6 +_,7 @@ this.finalizers.forEach(Runnable::run); } + private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper - public void print(JTextArea textArea, JScrollPane scrollPane, String line) { + public void print(final JTextArea console, final JScrollPane scrollPane, final String line) { if (!SwingUtilities.isEventDispatchThread()) { - SwingUtilities.invokeLater(() -> this.print(textArea, scrollPane, line)); -@@ -162,7 +_,7 @@ + SwingUtilities.invokeLater(() -> this.print(console, scrollPane, line)); +@@ -167,7 +_,7 @@ } try { @@ -48,7 +48,7 @@ } catch (BadLocationException var8) { } -@@ -171,4 +_,37 @@ +@@ -176,4 +_,37 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/server/gui/StatsComponent.java.patch b/paper-server/patches/sources/net/minecraft/server/gui/StatsComponent.java.patch index 40640f3fda1f..5e806ee764fb 100644 --- a/paper-server/patches/sources/net/minecraft/server/gui/StatsComponent.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/gui/StatsComponent.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/server/gui/StatsComponent.java +++ b/net/minecraft/server/gui/StatsComponent.java -@@ -32,8 +_,17 @@ +@@ -32,12 +_,21 @@ private void tick() { - long l = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + long usedRam = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + // Paper start - Improve ServerGUI + double[] tps = org.bukkit.Bukkit.getTPS(); + String[] tpsAvg = new String[tps.length]; @@ -11,14 +11,18 @@ + for (int g = 0; g < tps.length; g++) { + tpsAvg[g] = format(tps[g]); + } - this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)"; + this.msgs[0] = "Memory use: " + + usedRam / 1024L / 1024L + + " mb (" + + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + + "% free)"; this.msgs[1] = "Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"; + this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg); + // Paper end - Improve ServerGUI - this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory()); + this.values[this.vp++ & 0xFF] = (int)(usedRam * 100L / Runtime.getRuntime().maxMemory()); this.repaint(); } -@@ -62,4 +_,10 @@ +@@ -66,4 +_,10 @@ public void close() { this.timer.stop(); } diff --git a/paper-server/patches/sources/net/minecraft/server/jsonrpc/JsonRpcNotificationService.java.patch b/paper-server/patches/sources/net/minecraft/server/jsonrpc/JsonRpcNotificationService.java.patch index e8fa089602cf..e6ae83d7a698 100644 --- a/paper-server/patches/sources/net/minecraft/server/jsonrpc/JsonRpcNotificationService.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/jsonrpc/JsonRpcNotificationService.java.patch @@ -4,9 +4,9 @@ } @Override -- public void onGameRuleChanged(GameRule rule, T value) { -+ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, GameRule rule, T value) { // Paper - per-world game rules (add level param) +- public void onGameRuleChanged(final GameRule gameRule, final T value) { ++ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, final GameRule gameRule, final T value) { // Paper - per-world game rules (add level param) + if (level != level.getServer().overworld()) return; // Paper - per-world game rules - use overworld for vanilla protocol - this.broadcastNotification(OutgoingRpcMethods.GAMERULE_CHANGED, GameRulesService.getTypedRule(this.minecraftApi, rule, value)); + this.broadcastNotification(OutgoingRpcMethods.GAMERULE_CHANGED, GameRulesService.getTypedRule(this.minecraftApi, gameRule, value)); } diff --git a/paper-server/patches/sources/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java.patch index 92b7b4e23401..bafa895fc28d 100644 --- a/paper-server/patches/sources/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java.patch @@ -1,11 +1,20 @@ --- a/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java +++ b/net/minecraft/server/jsonrpc/internalapi/MinecraftGameRuleServiceImpl.java +@@ -15,7 +_,7 @@ + + public MinecraftGameRuleServiceImpl(final DedicatedServer server, final JsonRpcLogger jsonrpcLogger) { + this.server = server; +- this.gameRules = server.getGameRules(); ++ this.gameRules = server.overworld().getGameRules(); // Paper - per-world game rules - use overworld for vanilla protocol + this.jsonrpcLogger = jsonrpcLogger; + } + @@ -24,7 +_,7 @@ GameRule gameRule = update.gameRule(); - T object = this.gameRules.get(gameRule); - T object1 = update.value(); -- this.gameRules.set(gameRule, object1, this.server); -+ this.gameRules.set(gameRule, object1, this.server.overworld()); // Paper - per-world game rules - use overworld for vanilla protocol - this.jsonrpcLogger.log(client, "Game rule '{}' updated from '{}' to '{}'", gameRule.id(), gameRule.serialize(object), gameRule.serialize(object1)); + T oldValue = this.gameRules.get(gameRule); + T newValue = update.value(); +- this.gameRules.set(gameRule, newValue, this.server); ++ this.gameRules.set(gameRule, newValue, this.server.overworld()); // Paper - per-world game rules - use overworld for vanilla protocol + this.jsonrpcLogger + .log(clientInfo, "Game rule '{}' updated from '{}' to '{}'", gameRule.id(), gameRule.serialize(oldValue), gameRule.serialize(newValue)); return update; - } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch index dbd31018891f..40e8aed5c903 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch @@ -43,14 +43,14 @@ @@ -127,6 +_,7 @@ } else { - boolean flag = this.hasChangedSections; + boolean hadChangedSections = this.hasChangedSections; int sectionIndex = this.levelHeightAccessor.getSectionIndex(pos.getY()); + if (sectionIndex < 0 || sectionIndex >= this.changedBlocksPerSection.length) return false; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 - ShortSet set = this.changedBlocksPerSection[sectionIndex]; - if (set == null) { + ShortSet changedBlocksInSection = this.changedBlocksPerSection[sectionIndex]; + if (changedBlocksInSection == null) { this.hasChangedSections = true; -@@ -274,6 +_,38 @@ - chunkMap.onFullChunkStatusChange(this.pos, fullChunkStatus); +@@ -270,6 +_,38 @@ + scheduler.onFullChunkStatusChange(this.pos, status); } + // CraftBukkit start @@ -85,16 +85,16 @@ + } + // CraftBukkit end + - protected void updateFutures(ChunkMap chunkMap, Executor executor) { - FullChunkStatus fullChunkStatus = ChunkLevel.fullStatus(this.oldTicketLevel); - FullChunkStatus fullChunkStatus1 = ChunkLevel.fullStatus(this.ticketLevel); -@@ -281,12 +_,28 @@ - boolean isOrAfter1 = fullChunkStatus1.isOrAfter(FullChunkStatus.FULL); - this.wasAccessibleSinceLastSave |= isOrAfter1; - if (!isOrAfter && isOrAfter1) { + protected void updateFutures(final ChunkMap scheduler, final Executor mainThreadExecutor) { + FullChunkStatus oldFullStatus = ChunkLevel.fullStatus(this.oldTicketLevel); + FullChunkStatus newFullStatus = ChunkLevel.fullStatus(this.ticketLevel); +@@ -277,12 +_,28 @@ + boolean isAccessible = newFullStatus.isOrAfter(FullChunkStatus.FULL); + this.wasAccessibleSinceLastSave |= isAccessible; + if (!wasAccessible && isAccessible) { + int expectCreateCount = ++this.fullChunkCreateCount; // Paper - this.fullChunkFuture = chunkMap.prepareAccessibleChunk(this); - this.scheduleFullChunkPromotion(chunkMap, this.fullChunkFuture, executor, FullChunkStatus.FULL); + this.fullChunkFuture = scheduler.prepareAccessibleChunk(this); + this.scheduleFullChunkPromotion(scheduler, this.fullChunkFuture, mainThreadExecutor, FullChunkStatus.FULL); + // Paper start - cache ticking ready status + this.fullChunkFuture.thenAccept(chunkResult -> { + chunkResult.ifSuccess(chunk -> { @@ -108,7 +108,7 @@ this.addSaveDependency(this.fullChunkFuture); } - if (isOrAfter && !isOrAfter1) { + if (wasAccessible && !isAccessible) { + // Paper start + if (this.isFullChunkReady) { + ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkNotBorder(this.fullChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper @@ -117,10 +117,10 @@ this.fullChunkFuture.complete(UNLOADED_LEVEL_CHUNK); this.fullChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; } -@@ -296,11 +_,25 @@ - if (!isOrAfter2 && isOrAfter3) { - this.tickingChunkFuture = chunkMap.prepareTickingChunk(this); - this.scheduleFullChunkPromotion(chunkMap, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING); +@@ -292,11 +_,25 @@ + if (!wasTicking && isTicking) { + this.tickingChunkFuture = scheduler.prepareTickingChunk(this); + this.scheduleFullChunkPromotion(scheduler, this.tickingChunkFuture, mainThreadExecutor, FullChunkStatus.BLOCK_TICKING); + // Paper start - cache ticking ready status + this.tickingChunkFuture.thenAccept(chunkResult -> { + chunkResult.ifSuccess(chunk -> { @@ -129,11 +129,11 @@ + ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkTicking(chunk, this); + }); + }); -+ // Paper end ++ // Paper end - cache ticking ready status this.addSaveDependency(this.tickingChunkFuture); } - if (isOrAfter2 && !isOrAfter3) { + if (wasTicking && !isTicking) { - this.tickingChunkFuture.complete(UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isTickingReady) { @@ -144,10 +144,10 @@ this.tickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; } -@@ -313,11 +_,24 @@ +@@ -309,11 +_,24 @@ - this.entityTickingChunkFuture = chunkMap.prepareEntityTickingChunk(this); - this.scheduleFullChunkPromotion(chunkMap, this.entityTickingChunkFuture, executor, FullChunkStatus.ENTITY_TICKING); + this.entityTickingChunkFuture = scheduler.prepareEntityTickingChunk(this); + this.scheduleFullChunkPromotion(scheduler, this.entityTickingChunkFuture, mainThreadExecutor, FullChunkStatus.ENTITY_TICKING); + // Paper start - cache ticking ready status + this.entityTickingChunkFuture.thenAccept(chunkResult -> { + chunkResult.ifSuccess(chunk -> { @@ -159,7 +159,7 @@ this.addSaveDependency(this.entityTickingChunkFuture); } - if (isOrAfter4 && !isOrAfter5) { + if (wasEntityTicking && !isEntityTicking) { - this.entityTickingChunkFuture.complete(UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isEntityTickingReady) { @@ -170,17 +170,17 @@ this.entityTickingChunkFuture = UNLOADED_LEVEL_CHUNK_FUTURE; } -@@ -327,6 +_,26 @@ +@@ -323,6 +_,26 @@ this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel); this.oldTicketLevel = this.ticketLevel; + // CraftBukkit start + // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins. -+ if (!fullChunkStatus.isOrAfter(FullChunkStatus.FULL) && fullChunkStatus1.isOrAfter(FullChunkStatus.FULL)) { ++ if (!oldFullStatus.isOrAfter(FullChunkStatus.FULL) && newFullStatus.isOrAfter(FullChunkStatus.FULL)) { + this.getFullChunkFuture().thenAccept((either) -> { + LevelChunk chunk = (LevelChunk) either.orElse(null); + if (chunk != null) { -+ chunkMap.callbackExecutor.execute(() -> { ++ scheduler.callbackExecutor.execute(() -> { + chunk.loadCallback(); + }); + } @@ -191,7 +191,7 @@ + }); + + // Run callback right away if the future was already done -+ chunkMap.callbackExecutor.run(); ++ scheduler.callbackExecutor.run(); + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch index face92235b53..3f264811c58b 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch @@ -32,32 +32,32 @@ + // Paper end + public ChunkMap( - ServerLevel level, - LevelStorageSource.LevelStorageAccess levelStorageAccess, -@@ -180,13 +_,19 @@ + final ServerLevel level, + final LevelStorageSource.LevelStorageAccess levelStorage, +@@ -179,13 +_,19 @@ this.level = level; RegistryAccess registryAccess = level.registryAccess(); - long seed = level.getSeed(); -- if (generator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + long levelSeed = level.getSeed(); +- if (generator instanceof NoiseBasedChunkGenerator noiseGenerator) { + // CraftBukkit start - SPIGOT-7051: It's a rigged game! Use delegate for random state creation, otherwise it is not so random. + ChunkGenerator randomGenerator = generator; + if (randomGenerator instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator customChunkGenerator) { + randomGenerator = customChunkGenerator.getDelegate(); + } -+ if (randomGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { -+ // CraftBukkit end - this.randomState = RandomState.create(noiseBasedChunkGenerator.generatorSettings().value(), registryAccess.lookupOrThrow(Registries.NOISE), seed); ++ if (randomGenerator instanceof NoiseBasedChunkGenerator noiseGenerator) { ++ // CraftBukkit end + this.randomState = RandomState.create(noiseGenerator.generatorSettings().value(), registryAccess.lookupOrThrow(Registries.NOISE), levelSeed); } else { - this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), registryAccess.lookupOrThrow(Registries.NOISE), seed); + this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), registryAccess.lookupOrThrow(Registries.NOISE), levelSeed); } -- this.chunkGeneratorState = generator.createState(registryAccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, seed); -+ this.chunkGeneratorState = generator.createState(registryAccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, seed, level.spigotConfig); // Spigot +- this.chunkGeneratorState = generator.createState(registryAccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, levelSeed); ++ this.chunkGeneratorState = generator.createState(registryAccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, levelSeed, level.spigotConfig); // Spigot this.mainThreadExecutor = mainThreadExecutor; - ConsecutiveExecutor consecutiveExecutor = new ConsecutiveExecutor(dispatcher, "worldgen"); + ConsecutiveExecutor worldgen = new ConsecutiveExecutor(executor, "worldgen"); this.chunkStatusListener = chunkStatusListener; -@@ -215,6 +_,12 @@ - this.chunksToEagerlySave.add(chunkPos.toLong()); +@@ -212,6 +_,12 @@ + this.chunksToEagerlySave.add(chunkPos.pack()); } + // Paper start @@ -69,47 +69,47 @@ protected ChunkGenerator generator() { return this.worldGenContext.generator(); } -@@ -357,9 +_,9 @@ - } - ); - stringBuilder.append("Updating:").append(System.lineSeparator()); -- this.updatingChunkMap.values().forEach(consumer); -+ ca.spottedleaf.moonrise.common.PlatformHooks.get().getUpdatingChunkHolders(this.level).forEach(consumer); // Paper - stringBuilder.append("Visible:").append(System.lineSeparator()); -- this.visibleChunkMap.values().forEach(consumer); -+ ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level).forEach(consumer); // Paper - CrashReport crashReport = CrashReport.forThrowable(exception, "Chunk loading"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk loading"); - crashReportCategory.setDetail("Details", details); -@@ -394,6 +_,7 @@ - holder.setTicketLevel(newLevel); +@@ -348,9 +_,9 @@ + } + }); + sb.append("Updating:").append(System.lineSeparator()); +- this.updatingChunkMap.values().forEach(addToDebug); ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().getUpdatingChunkHolders(this.level).forEach(addToDebug); // Paper + sb.append("Visible:").append(System.lineSeparator()); +- this.visibleChunkMap.values().forEach(addToDebug); ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level).forEach(addToDebug); // Paper + CrashReport report = CrashReport.forThrowable(exception, "Chunk loading"); + CrashReportCategory category = report.addCategory("Chunk loading"); + category.setDetail("Details", details); +@@ -385,6 +_,7 @@ + chunk.setTicketLevel(level); } else { - holder = new ChunkHolder(new ChunkPos(chunkPos), newLevel, this.level, this.lightEngine, this::onLevelChange, this); -+ ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, holder); // Paper + chunk = new ChunkHolder(ChunkPos.unpack(node), level, this.level, this.lightEngine, this::onLevelChange, this); ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, chunk); // Paper } - this.updatingChunkMap.put(chunkPos, holder); -@@ -422,8 +_,8 @@ + this.updatingChunkMap.put(node, chunk); +@@ -413,8 +_,8 @@ - protected void saveAllChunks(boolean flush) { - if (flush) { -- List list = this.visibleChunkMap + protected void saveAllChunks(final boolean flushStorage) { + if (flushStorage) { +- List chunksToSave = this.visibleChunkMap - .values() -+ List list = ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level) // Paper - moonrise ++ List chunksToSave = ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level) // Paper - moonrise + //.values() // Paper - moonrise .stream() .filter(ChunkHolder::wasAccessibleSinceLastSave) .peek(ChunkHolder::refreshAccessibility) -@@ -449,7 +_,7 @@ +@@ -440,7 +_,7 @@ this.nextChunkSaveTime.clear(); - long millis = Util.getMillis(); + long now = Util.getMillis(); -- for (ChunkHolder chunkHolder : this.visibleChunkMap.values()) { -+ for (ChunkHolder chunkHolder : ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level)) { // Paper - this.saveChunkIfNeeded(chunkHolder, millis); +- for (ChunkHolder chunk : this.visibleChunkMap.values()) { ++ for (ChunkHolder chunk : ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level)) { // Paper + this.saveChunkIfNeeded(chunk, now); } } -@@ -470,6 +_,7 @@ +@@ -461,6 +_,7 @@ public boolean hasWork() { return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() @@ -117,31 +117,31 @@ || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() -@@ -528,7 +_,11 @@ - this.scheduleUnload(chunkPos, chunkHolder); +@@ -519,7 +_,11 @@ + this.scheduleUnload(pos, chunkHolder); } else { - ChunkAccess latestChunk = chunkHolder.getLatestChunk(); -- if (this.pendingUnloads.remove(chunkPos, chunkHolder) && latestChunk != null) { + ChunkAccess chunk = chunkHolder.getLatestChunk(); +- if (this.pendingUnloads.remove(pos, chunkHolder) && chunk != null) { + // Paper start + boolean removed; -+ if ((removed = this.pendingUnloads.remove(chunkPos, chunkHolder)) && latestChunk != null) { ++ if ((removed = this.pendingUnloads.remove(pos, chunkHolder)) && chunk != null) { + ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderDelete(this.level, chunkHolder); + // Paper end - if (latestChunk instanceof LevelChunk levelChunk) { + if (chunk instanceof LevelChunk levelChunk) { levelChunk.setLoaded(false); } -@@ -541,7 +_,9 @@ - this.lightEngine.updateChunkStatus(latestChunk.getPos()); +@@ -532,7 +_,9 @@ + this.lightEngine.updateChunkStatus(chunk.getPos()); this.lightEngine.tryScheduleUpdate(); - this.nextChunkSaveTime.remove(latestChunk.getPos().toLong()); + this.nextChunkSaveTime.remove(chunk.getPos().pack()); - } + } else if (removed) { // Paper start + ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderDelete(this.level, chunkHolder); + } // Paper end } - }, this.unloadQueue::add).whenComplete((_void, error) -> { - if (error != null) { -@@ -851,7 +_,7 @@ + }, this.unloadQueue::add).whenComplete((ignored, throwable) -> { + if (throwable != null) { +@@ -841,7 +_,7 @@ } public int size() { @@ -150,115 +150,118 @@ } public net.minecraft.server.level.DistanceManager getDistanceManager() { -@@ -878,10 +_,10 @@ +@@ -868,10 +_,10 @@ .addColumn("fluid_ticks") - .build(writer); + .build(output); - for (Entry entry : this.visibleChunkMap.long2ObjectEntrySet()) { -- long longKey = entry.getLongKey(); +- long posKey = entry.getLongKey(); +- ChunkPos pos = ChunkPos.unpack(posKey); +- ChunkHolder holder = entry.getValue(); + for (ChunkHolder entry : ca.spottedleaf.moonrise.common.PlatformHooks.get().getVisibleChunkHolders(this.level)) { // Paper - Moonrise -+ long longKey = entry.pos.toLong(); // Paper - Moonrise - ChunkPos chunkPos = new ChunkPos(longKey); -- ChunkHolder chunkHolder = entry.getValue(); -+ ChunkHolder chunkHolder = entry; // Paper - Moonrise - Optional optional = Optional.ofNullable(chunkHolder.getLatestChunk()); - Optional optional1 = optional.flatMap(chunk -> chunk instanceof LevelChunk ? Optional.of((LevelChunk)chunk) : Optional.empty()); - csvOutput.writeRow( -@@ -925,12 +_,12 @@ ++ long posKey = entry.pos.pack(); // Paper - Moonrise ++ ChunkPos pos = entry.pos; // Paper - Moonrise ++ ChunkHolder holder = entry; // Paper - Moonrise + Optional chunk = Optional.ofNullable(holder.getLatestChunk()); + Optional fullChunk = chunk.flatMap( + chunkAccess -> chunkAccess instanceof LevelChunk ? Optional.of((LevelChunk)chunkAccess) : Optional.empty() +@@ -920,14 +_,14 @@ + return this.upgradeChunkTag( + tag, + -1, +- getChunkDataFixContextTag(this.level.dimension(), this.generator().getTypeNameForDataFixer()), ++ getChunkDataFixContextTag(this.level.getTypeKey(), this.generator().getTypeNameForDataFixer()), // CraftBukkit + SharedConstants.getCurrentVersion().dataVersion().version() + ); } - private CompoundTag upgradeChunkTag(CompoundTag tag) { -- return this.upgradeChunkTag(tag, -1, getChunkDataFixContextTag(this.level.dimension(), this.generator().getTypeNameForDataFixer())); -+ return this.upgradeChunkTag(tag, -1, getChunkDataFixContextTag(this.level.getTypeKey(), this.generator().getTypeNameForDataFixer()), this.level); // CraftBukkit +- public static CompoundTag getChunkDataFixContextTag(final ResourceKey dimension, final Optional generatorIdentifier) { ++ public static CompoundTag getChunkDataFixContextTag(final ResourceKey stemKey, final Optional generatorIdentifier) { // CraftBukkit + CompoundTag contextTag = new CompoundTag(); +- contextTag.putString("dimension", dimension.identifier().toString()); ++ contextTag.putString("dimension", stemKey.identifier().toString()); // CraftBukkit + generatorIdentifier.ifPresent(identifier -> contextTag.putString("generator", identifier.toString())); + return contextTag; } - -- public static CompoundTag getChunkDataFixContextTag(ResourceKey dimension, Optional>> generator) { -+ public static CompoundTag getChunkDataFixContextTag(ResourceKey stemKey, Optional>> generator) { // CraftBukkit - CompoundTag compoundTag = new CompoundTag(); -- compoundTag.putString("dimension", dimension.identifier().toString()); -+ compoundTag.putString("dimension", stemKey.identifier().toString()); // CraftBukkit - generator.ifPresent(resourceKey -> compoundTag.putString("generator", resourceKey.identifier().toString())); - return compoundTag; - } -@@ -942,7 +_,7 @@ - ChunkHolder chunkHolder = this.visibleChunkMap.get(spawnCandidateChunks.nextLong()); - if (chunkHolder != null) { - LevelChunk tickingChunk = chunkHolder.getTickingChunk(); -- if (tickingChunk != null && this.anyPlayerCloseEnoughForSpawningInternal(chunkHolder.getPos())) { -+ if (tickingChunk != null && this.anyPlayerCloseEnoughForSpawningInternal(chunkHolder.getPos(), true)) { // Spigot - output.add(tickingChunk); +@@ -939,7 +_,7 @@ + ChunkHolder holder = this.visibleChunkMap.get(spawnCandidateChunks.nextLong()); + if (holder != null) { + LevelChunk chunk = holder.getTickingChunk(); +- if (chunk != null && this.anyPlayerCloseEnoughForSpawningInternal(holder.getPos())) { ++ if (chunk != null && this.anyPlayerCloseEnoughForSpawningInternal(holder.getPos(), true)) { // Spigot + output.add(chunk); } } -@@ -962,8 +_,14 @@ +@@ -959,8 +_,14 @@ } - public boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkPos) { + public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) { + // Spigot start -+ return this.anyPlayerCloseEnoughForSpawning(chunkPos, false); ++ return this.anyPlayerCloseEnoughForSpawning(pos, false); + } + -+ boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkPos, boolean reducedRange) { - TriState triState = this.distanceManager.hasPlayersNearby(chunkPos.toLong()); -- return triState == TriState.DEFAULT ? this.anyPlayerCloseEnoughForSpawningInternal(chunkPos) : triState.toBoolean(true); -+ return triState == TriState.DEFAULT ? this.anyPlayerCloseEnoughForSpawningInternal(chunkPos, reducedRange) : triState.toBoolean(true); ++ boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos, boolean reducedRange) { + TriState triState = this.distanceManager.hasPlayersNearby(pos.pack()); +- return triState == TriState.DEFAULT ? this.anyPlayerCloseEnoughForSpawningInternal(pos) : triState.toBoolean(true); ++ return triState == TriState.DEFAULT ? this.anyPlayerCloseEnoughForSpawningInternal(pos, reducedRange) : triState.toBoolean(true); + // Spigot end } - boolean anyPlayerCloseEnoughTo(BlockPos pos, int radius) { -@@ -979,8 +_,24 @@ + boolean anyPlayerCloseEnoughTo(final BlockPos pos, final int maxDistance) { +@@ -976,8 +_,24 @@ } - private boolean anyPlayerCloseEnoughForSpawningInternal(ChunkPos chunkPos) { + private boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos) { + // Spigot start -+ return this.anyPlayerCloseEnoughForSpawningInternal(chunkPos, false); ++ return this.anyPlayerCloseEnoughForSpawningInternal(pos, false); + } + -+ private boolean anyPlayerCloseEnoughForSpawningInternal(ChunkPos chunkPos, boolean reducedRange) { ++ private boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos, final boolean reducedRange) { + double blockRange; // Paper - use from event + // Spigot end - for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { -- if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos)) { + for (ServerPlayer player : this.playerMap.getAllPlayers()) { +- if (this.playerIsCloseEnoughForSpawning(player, pos)) { + // Paper start - PlayerNaturallySpawnCreaturesEvent + com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; -+ blockRange = 16384.0D; ++ blockRange = 16384.0; + if (reducedRange) { -+ event = serverPlayer.playerNaturallySpawnedEvent; ++ event = player.playerNaturallySpawnedEvent; + if (event == null || event.isCancelled()) continue; + blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); + } -+ if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos, blockRange)) { ++ if (this.playerIsCloseEnoughForSpawning(player, pos, blockRange)) { + // Paper end - PlayerNaturallySpawnCreaturesEvent return true; } } -@@ -996,7 +_,7 @@ +@@ -993,7 +_,7 @@ Builder builder = ImmutableList.builder(); - for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) { -- if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos)) { -+ if (this.playerIsCloseEnoughForSpawning(serverPlayer, chunkPos, 16384.0D)) { // Spigot - builder.add(serverPlayer); + for (ServerPlayer player : this.playerMap.getAllPlayers()) { +- if (this.playerIsCloseEnoughForSpawning(player, pos)) { ++ if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0)) { // Spigot + builder.add(player); } } -@@ -1005,12 +_,12 @@ +@@ -1002,12 +_,12 @@ } } -- private boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos chunkPos) { -+ private boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos chunkPos, double range) { // Spigot +- private boolean playerIsCloseEnoughForSpawning(final ServerPlayer player, final ChunkPos pos) { ++ private boolean playerIsCloseEnoughForSpawning(final ServerPlayer player, final ChunkPos pos, final double range) { // Spigot if (player.isSpectator()) { return false; } else { - double d = euclideanDistanceSquared(chunkPos, player.position()); -- return d < 16384.0; -+ return d < range; // Spigot + double distanceToChunk = euclideanDistanceSquared(pos, player.position()); +- return distanceToChunk < 16384.0; ++ return distanceToChunk < range; // Spigot } } -@@ -1141,9 +_,19 @@ +@@ -1136,9 +_,19 @@ } - public void addEntity(Entity entity) { + public void addEntity(final Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot + // Paper start - ignore and warn about illegal addEntity calls instead of crashing server + if (!entity.valid || entity.level() != this.level || this.entityMap.containsKey(entity.getId())) { @@ -270,77 +273,75 @@ + if (entity instanceof ServerPlayer && ((ServerPlayer) entity).suppressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets if (!(entity instanceof EnderDragonPart)) { EntityType type = entity.getType(); - int i = type.clientTrackingRange() * 16; -+ i = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i); // Spigot - if (i != 0) { + int range = type.clientTrackingRange() * 16; ++ range = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, range); // Spigot + if (range != 0) { int updateInterval = type.updateInterval(); if (this.entityMap.containsKey(entity.getId())) { -@@ -1167,6 +_,7 @@ +@@ -1162,6 +_,7 @@ } - protected void removeEntity(Entity entity) { + protected void removeEntity(final Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot - if (entity instanceof ServerPlayer serverPlayer) { - this.updatePlayerStatus(serverPlayer, false); - -@@ -1326,10 +_,10 @@ - final Entity entity; - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = Sets.newIdentityHashSet(); -+ public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + if (entity instanceof ServerPlayer player) { + this.updatePlayerStatus(player, false); +@@ -1329,8 +_,8 @@ public TrackedEntity(final Entity entity, final int range, final int updateInterval, final boolean trackDelta) { + Objects.requireNonNull(ChunkMap.this); + super(); +- this.seenBy = Sets.newIdentityHashSet(); - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this); ++ this.seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this, this.seenBy); // Paper this.entity = entity; this.range = range; this.lastSectionPos = SectionPos.of(entity); -@@ -1376,6 +_,7 @@ +@@ -1377,6 +_,7 @@ } - public void removePlayer(ServerPlayer player) { + public void removePlayer(final ServerPlayer player) { + org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot if (this.seenBy.remove(player.connection)) { this.serverEntity.removePairing(player); if (this.seenBy.isEmpty()) { -@@ -1385,23 +_,45 @@ +@@ -1386,23 +_,47 @@ } - public void updatePlayer(ServerPlayer player) { + public void updatePlayer(final ServerPlayer player) { + org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (player != this.entity) { -- Vec3 vec3 = player.position().subtract(this.entity.position()); +- Vec3 deltaToPlayer = player.position().subtract(this.entity.position()); + // Paper start - remove allocation of Vec3D here -+ // Vec3 vec3 = player.position().subtract(this.entity.position()); -+ double vec3_dx = player.getX() - this.entity.getX(); -+ double vec3_dz = player.getZ() - this.entity.getZ(); ++ // Vec3 deltaToPlayer = player.position().subtract(this.entity.position()); ++ double deltaToPlayerX = player.getX() - this.entity.getX(); ++ double deltaToPlayerZ = player.getZ() - this.entity.getZ(); + // Paper end - remove allocation of Vec3D here int playerViewDistance = ChunkMap.this.getPlayerViewDistance(player); - double d = Math.min(this.getEffectiveRange(), playerViewDistance * 16); -- double d1 = vec3.x * vec3.x + vec3.z * vec3.z; -+ double d1 = vec3_dx * vec3_dx + vec3_dz * vec3_dz; // Paper - double d2 = d * d; -- boolean flag = d1 <= d2 -- && this.entity.broadcastToPlayer(player) -- && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); + double visibleRange = Math.min(this.getEffectiveRange(), playerViewDistance * 16); +- double distanceSquared = deltaToPlayer.x * deltaToPlayer.x + deltaToPlayer.z * deltaToPlayer.z; ++ double distanceSquared = deltaToPlayerX * deltaToPlayerX + deltaToPlayerZ * deltaToPlayerZ; // Paper + double rangeSquared = visibleRange * visibleRange; +- boolean visibleToPlayer = distanceSquared <= rangeSquared + // Paper start - Configurable entity tracking range by Y -+ boolean flag = d1 <= d2; -+ if (flag && level.paperConfig().entities.trackingRangeY.enabled) { ++ boolean visibleToPlayer = distanceSquared <= rangeSquared; ++ if (visibleToPlayer && level.paperConfig().entities.trackingRangeY.enabled) { + double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1); + if (rangeY != -1) { -+ double vec3_dy = player.getY() - this.entity.getY(); -+ flag = vec3_dy * vec3_dy <= rangeY * rangeY; ++ double deltaToPlayerY = player.getY() - this.entity.getY(); ++ visibleToPlayer = deltaToPlayerY * deltaToPlayerY <= rangeY * rangeY; + } + } -+ flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); ++ visibleToPlayer = visibleToPlayer + && this.entity.broadcastToPlayer(player) + && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x(), this.entity.chunkPosition().z()); + // Paper end - Configurable entity tracking range by Y + // CraftBukkit start - respect vanish API -+ if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits -+ flag = false; ++ if (visibleToPlayer && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits ++ visibleToPlayer = false; + } + // CraftBukkit end - if (flag) { + if (visibleToPlayer) { if (this.seenBy.add(player.connection)) { + // Paper start - entity tracking events + if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) { @@ -355,11 +356,11 @@ } } else { this.removePlayer(player); -@@ -1418,6 +_,7 @@ +@@ -1419,6 +_,7 @@ - for (Entity entity : this.entity.getIndirectPassengers()) { - int i1 = entity.getType().clientTrackingRange() * 16; -+ i1 = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i1); // Paper - if (i1 > i) { - i = i1; + for (Entity passenger : this.entity.getIndirectPassengers()) { + int passengerRange = passenger.getType().clientTrackingRange() * 16; ++ passengerRange = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, passengerRange); // Paper + if (passengerRange > effectiveRange) { + effectiveRange = passengerRange; } diff --git a/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch b/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch index 0ef527512714..0b09c2876f86 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/server/level/DistanceManager.java +++ b/net/minecraft/server/level/DistanceManager.java -@@ -72,6 +_,12 @@ +@@ -73,6 +_,12 @@ } if (!this.chunksToUpdateFutures.isEmpty()) { + // CraftBukkit start - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus -+ for (final ChunkHolder chunkHolder : this.chunksToUpdateFutures) { -+ chunkHolder.callEventIfUnloading(chunkMap); ++ for (final ChunkHolder chunksToUpdateFuture : this.chunksToUpdateFutures) { ++ chunksToUpdateFuture.callEventIfUnloading(scheduler); + } + // CraftBukkit end - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus + - for (ChunkHolder chunkHolder : this.chunksToUpdateFutures) { - chunkHolder.updateHighestAllowedStatus(chunkMap); + for (ChunkHolder chunksToUpdateFuture : this.chunksToUpdateFutures) { + chunksToUpdateFuture.updateHighestAllowedStatus(scheduler); } -@@ -121,8 +_,10 @@ - ChunkPos chunkPos = sectionPos.chunk(); - long packedChunkPos = chunkPos.toLong(); - ObjectSet set = this.playersPerChunk.get(packedChunkPos); -- set.remove(player); -- if (set.isEmpty()) { +@@ -120,8 +_,10 @@ + ChunkPos chunk = pos.chunk(); + long chunkPos = chunk.pack(); + ObjectSet chunkPlayers = this.playersPerChunk.get(chunkPos); +- chunkPlayers.remove(player); +- if (chunkPlayers.isEmpty()) { + // Paper start - some state corruption happens here, don't crash, clean up gracefully -+ if (set != null) set.remove(player); -+ if (set == null || set.isEmpty()) { ++ if (chunkPlayers != null) chunkPlayers.remove(player); ++ if (chunkPlayers == null || chunkPlayers.isEmpty()) { + // Paper end - some state corruption happens here, don't crash, clean up gracefully - this.playersPerChunk.remove(packedChunkPos); - this.naturalSpawnChunkCounter.update(packedChunkPos, Integer.MAX_VALUE, false); - this.playerTicketManager.update(packedChunkPos, Integer.MAX_VALUE, false); + this.playersPerChunk.remove(chunkPos); + this.naturalSpawnChunkCounter.update(chunkPos, Integer.MAX_VALUE, false); + this.playerTicketManager.update(chunkPos, Integer.MAX_VALUE, false); diff --git a/paper-server/patches/sources/net/minecraft/server/level/PlayerSpawnFinder.java.patch b/paper-server/patches/sources/net/minecraft/server/level/PlayerSpawnFinder.java.patch index ba090aa9250e..b9e3d08db459 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/PlayerSpawnFinder.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/PlayerSpawnFinder.java.patch @@ -3,9 +3,9 @@ @@ -48,7 +_,7 @@ } - public static CompletableFuture findSpawn(ServerLevel level, BlockPos pos) { + public static CompletableFuture findSpawn(final ServerLevel level, final BlockPos spawnSuggestion) { - if (level.dimensionType().hasSkyLight() && level.getServer().getWorldData().getGameType() != GameType.ADVENTURE) { + if (level.dimensionType().hasSkyLight() && level.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit - int max = Math.max(0, level.getGameRules().get(GameRules.RESPAWN_RADIUS)); - int floor = Mth.floor(level.getWorldBorder().getDistanceToBorder(pos.getX(), pos.getZ())); - if (floor < max) { + int radius = Math.max(0, level.getGameRules().get(GameRules.RESPAWN_RADIUS)); + int distToBorder = Mth.floor(level.getWorldBorder().getDistanceToBorder(spawnSuggestion.getX(), spawnSuggestion.getZ())); + if (distToBorder < radius) { diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch index 90afddb38210..bb67c8705f5e 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -67,6 +_,7 @@ +@@ -66,6 +_,7 @@ private final TicketStorage ticketStorage; private long lastInhabitedUpdate; public boolean spawnEnemies = true; @@ -8,7 +8,7 @@ private static final int CACHE_SIZE = 4; private final long[] lastChunkPos = new long[4]; private final @Nullable ChunkStatus[] lastChunkStatus = new ChunkStatus[4]; -@@ -75,6 +_,13 @@ +@@ -74,6 +_,13 @@ private final Set chunkHoldersToBroadcast = new ReferenceOpenHashSet<>(); @VisibleForDebug private NaturalSpawner.@Nullable SpawnState lastSpawnState; @@ -21,14 +21,14 @@ + // Paper end public ServerChunkCache( - ServerLevel level, -@@ -123,6 +_,64 @@ + final ServerLevel level, +@@ -122,6 +_,64 @@ this.clearCache(); } + // CraftBukkit start - properly implement isChunkLoaded + public boolean isChunkLoaded(int chunkX, int chunkZ) { -+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(ChunkPos.asLong(chunkX, chunkZ)); ++ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(ChunkPos.pack(chunkX, chunkZ)); + if (chunk == null) { + return false; + } @@ -46,7 +46,7 @@ + + @Nullable + public ChunkAccess getChunkAtImmediately(int x, int z) { -+ ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); ++ ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.pack(x, z)); + if (holder == null) { + return null; + } @@ -66,7 +66,7 @@ + // Note: Partially copied from the getChunkAt method below + @Nullable + public LevelChunk getChunkAtIfCachedImmediately(int x, int z) { -+ long k = ChunkPos.asLong(x, z); ++ long k = ChunkPos.pack(x, z); + + // Note: Bypass cache since we need to check ticket level, and to make this MT-Safe + @@ -80,57 +80,57 @@ + + @Nullable + public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) { -+ return this.fullChunks.get(ChunkPos.asLong(x, z)); ++ return this.fullChunks.get(ChunkPos.pack(x, z)); + } + // Paper end + @Override public ThreadedLevelLightEngine getLightEngine() { return this.lightEngine; -@@ -156,7 +_,7 @@ +@@ -155,7 +_,7 @@ for (int i = 0; i < 4; i++) { - if (packedChunkPos == this.lastChunkPos[i] && chunkStatus == this.lastChunkStatus[i]) { + if (pos == this.lastChunkPos[i] && targetStatus == this.lastChunkStatus[i]) { ChunkAccess chunkAccess = this.lastChunk[i]; -- if (chunkAccess != null || !requireChunk) { +- if (chunkAccess != null || !loadOrGenerate) { + if (chunkAccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime return chunkAccess; } } -@@ -165,6 +_,7 @@ - profilerFiller.incrementCounter("getChunkCacheMiss"); - CompletableFuture> chunkFutureMainThread = this.getChunkFutureMainThread(x, z, chunkStatus, requireChunk); - this.mainThreadProcessor.managedBlock(chunkFutureMainThread::isDone); +@@ -164,6 +_,7 @@ + profiler.incrementCounter("getChunkCacheMiss"); + CompletableFuture> serverFuture = this.getChunkFutureMainThread(x, z, targetStatus, loadOrGenerate); + this.mainThreadProcessor.managedBlock(serverFuture::isDone); + // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads - ChunkResult chunkResult = chunkFutureMainThread.join(); - ChunkAccess chunkAccess1 = chunkResult.orElse(null); - if (chunkAccess1 == null && requireChunk) { -@@ -235,7 +_,15 @@ - long packedChunkPos = chunkPos.toLong(); - int i = ChunkLevel.byStatus(chunkStatus); - ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(packedChunkPos); -- if (requireChunk) { + ChunkResult chunkResult = serverFuture.join(); + ChunkAccess chunk = chunkResult.orElse(null); + if (chunk == null && loadOrGenerate) { +@@ -236,7 +_,15 @@ + long key = pos.pack(); + int targetTicketLevel = ChunkLevel.byStatus(targetStatus); + ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(key); +- if (loadOrGenerate) { + // CraftBukkit start - don't add new ticket for currently unloading chunk + boolean currentlyUnloading = false; -+ if (visibleChunkIfPresent != null) { -+ FullChunkStatus oldChunkState = ChunkLevel.fullStatus(visibleChunkIfPresent.oldTicketLevel); -+ FullChunkStatus currentChunkState = ChunkLevel.fullStatus(visibleChunkIfPresent.getTicketLevel()); ++ if (chunkHolder != null) { ++ FullChunkStatus oldChunkState = ChunkLevel.fullStatus(chunkHolder.oldTicketLevel); ++ FullChunkStatus currentChunkState = ChunkLevel.fullStatus(chunkHolder.getTicketLevel()); + currentlyUnloading = (oldChunkState.isOrAfter(FullChunkStatus.FULL) && !currentChunkState.isOrAfter(FullChunkStatus.FULL)); + } -+ if (requireChunk && !currentlyUnloading) { ++ if (loadOrGenerate && !currentlyUnloading) { + // CraftBukkit end - this.addTicket(new Ticket(TicketType.UNKNOWN, i), chunkPos); - if (this.chunkAbsent(visibleChunkIfPresent, i)) { - ProfilerFiller profilerFiller = Profiler.get(); -@@ -255,7 +_,7 @@ + this.addTicket(new Ticket(TicketType.UNKNOWN, targetTicketLevel), pos); + if (this.chunkAbsent(chunkHolder, targetTicketLevel)) { + ProfilerFiller profiler = Profiler.get(); +@@ -256,7 +_,7 @@ } - private boolean chunkAbsent(@Nullable ChunkHolder chunkHolder, int status) { -- return chunkHolder == null || chunkHolder.getTicketLevel() > status; -+ return chunkHolder == null || chunkHolder.oldTicketLevel > status; // CraftBukkit using oldTicketLevel for isLoaded checks + private boolean chunkAbsent(final @Nullable ChunkHolder chunkHolder, final int targetTicketLevel) { +- return chunkHolder == null || chunkHolder.getTicketLevel() > targetTicketLevel; ++ return chunkHolder == null || chunkHolder.oldTicketLevel > targetTicketLevel; // CraftBukkit - using oldTicketLevel for isLoaded checks } @Override -@@ -309,17 +_,39 @@ +@@ -310,17 +_,39 @@ @Override public void close() throws IOException { @@ -144,7 +144,7 @@ + this.save(true); + } + // CraftBukkit end - this.dataStorage.close(); + this.savedDataStorage.close(); this.lightEngine.close(); this.chunkMap.close(); } @@ -164,57 +164,57 @@ + // CraftBukkit end + @Override - public void tick(BooleanSupplier hasTimeLeft, boolean tickChunks) { - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("purge"); + public void tick(final BooleanSupplier haveTime, final boolean tickChunks) { + ProfilerFiller profiler = Profiler.get(); + profiler.push("purge"); - if (this.level.tickRateManager().runsNormally() || !tickChunks) { + if (this.level.tickRateManager().runsNormally() || !tickChunks || this.level.spigotConfig.unloadFrozenChunks) { // Spigot this.ticketStorage.purgeStaleTickets(this.chunkMap); } -@@ -375,12 +_,20 @@ - naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap) +@@ -376,12 +_,20 @@ + chunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap) ); - this.lastSpawnState = spawnState; -- boolean flag = this.level.getGameRules().get(GameRules.SPAWN_MOBS); -+ boolean flag = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.players().isEmpty(); // CraftBukkit - int i = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED); - List filteredSpawningCategories; -- if (flag) { -- boolean flag1 = this.level.getGameTime() % 400L == 0L; -- filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, true, this.spawnEnemies, flag1); -+ if (flag && (this.spawnEnemies || this.spawnFriendlies)) { // Paper + this.lastSpawnState = spawnCookie; +- boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS); ++ boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.players().isEmpty(); // CraftBukkit + int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED); + List spawningCategories; +- if (doMobSpawning) { +- boolean spawnPersistent = this.level.getGameTime() % 400L == 0L; +- spawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnCookie, true, this.spawnEnemies, spawnPersistent); ++ if (doMobSpawning && (this.spawnEnemies || this.spawnFriendlies)) { // Paper + // Paper start - PlayerNaturallySpawnCreaturesEvent -+ for (ServerPlayer entityPlayer : this.level.players()) { -+ int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, entityPlayer.getBukkitEntity().getViewDistance()); ++ for (ServerPlayer player : this.level.players()) { ++ int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, player.getBukkitEntity().getViewDistance()); + chunkRange = Math.min(chunkRange, 8); -+ entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange); -+ entityPlayer.playerNaturallySpawnedEvent.callEvent(); ++ player.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte) chunkRange); ++ player.playerNaturallySpawnedEvent.callEvent(); + } + // Paper end - PlayerNaturallySpawnCreaturesEvent -+ boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit -+ filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, this.spawnFriendlies, this.spawnEnemies, flag1, this.level); // CraftBukkit ++ boolean spawnPersistent = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit ++ spawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnCookie, this.spawnFriendlies, this.spawnEnemies, spawnPersistent, this.level); // CraftBukkit } else { - filteredSpawningCategories = List.of(); + spawningCategories = List.of(); } -@@ -553,7 +_,13 @@ +@@ -556,7 +_,13 @@ @Override - public void setSpawnSettings(boolean spawnSettings) { + public void setSpawnSettings(final boolean spawnEnemies) { + // CraftBukkit start -+ this.setSpawnSettings(spawnSettings, this.spawnFriendlies); ++ this.setSpawnSettings(spawnEnemies, this.spawnFriendlies); + } -+ public void setSpawnSettings(boolean spawnSettings, boolean spawnFriendlies) { - this.spawnEnemies = spawnSettings; ++ public void setSpawnSettings(final boolean spawnEnemies, final boolean spawnFriendlies) { + this.spawnEnemies = spawnEnemies; + this.spawnFriendlies = spawnFriendlies; + // CraftBukkit end } - public String getChunkDebugData(ChunkPos chunkPos) { -@@ -625,12 +_,18 @@ + public String getChunkDebugData(final ChunkPos pos) { +@@ -624,12 +_,18 @@ @Override - public boolean pollTask() { + protected boolean pollTask() { + try { // CraftBukkit - process pending Chunk loadCallback() and unloadCallback() after each run task if (ServerChunkCache.this.runDistanceManagerUpdates()) { return true; diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch index d0eb6ed42506..5a700ce445d0 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java -@@ -65,12 +_,14 @@ +@@ -65,14 +_,17 @@ private Vec3 lastSentMovement; private int tickCount; private int teleportDelay; @@ -11,15 +11,17 @@ private @Nullable List> trackedDataValues; + private final Set trackedPlayers; // Paper -- public ServerEntity(ServerLevel level, Entity entity, int updateInterval, boolean trackDelta, ServerEntity.Synchronizer synchronizer) { -+ public ServerEntity(ServerLevel level, Entity entity, int updateInterval, boolean trackDelta, ServerEntity.Synchronizer synchronizer, final Set trackedPlayers) { // Paper + public ServerEntity( + final ServerLevel level, final Entity entity, final int updateInterval, final boolean trackDelta, final ServerEntity.Synchronizer synchronizer ++ , final Set trackedPlayers // Paper + ) { + this.trackedPlayers = trackedPlayers; // Paper this.level = level; this.synchronizer = synchronizer; this.entity = entity; -@@ -94,16 +_,22 @@ - new ClientboundSetPassengersPacket(this.entity), - serverPlayer1 -> passengers.contains(serverPlayer1) == this.lastPassengers.contains(serverPlayer1) +@@ -95,16 +_,22 @@ + .sendToTrackingPlayersFiltered( + new ClientboundSetPassengersPacket(this.entity), player -> passengers.contains(player) == this.lastPassengers.contains(player) ); + // Paper start - Allow riding players + if (this.entity instanceof ServerPlayer player) { @@ -29,36 +31,36 @@ this.lastPassengers = passengers; } -- if (this.entity instanceof ItemFrame itemFrame && this.tickCount % 10 == 0) { -+ if (!this.trackedPlayers.isEmpty() && this.entity instanceof ItemFrame itemFrame /*&& this.tickCount % 10 == 0*/) { // CraftBukkit - moved tickCount below // Paper - Perf: Only tick item frames if players can see it - ItemStack item = itemFrame.getItem(); -- if (item.getItem() instanceof MapItem) { -- MapId mapId = item.get(DataComponents.MAP_ID); -+ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && item.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable -+ MapId mapId = itemFrame.cachedMapId; // Paper - Perf: Cache map ids on item frames - MapItemSavedData savedData = MapItem.getSavedData(mapId, this.level); - if (savedData != null) { -- for (ServerPlayer serverPlayer : this.level.players()) { +- if (this.entity instanceof ItemFrame frame && this.tickCount % 10 == 0) { ++ if (!this.trackedPlayers.isEmpty() && this.entity instanceof ItemFrame frame /*&& this.tickCount % 10 == 0*/) { // CraftBukkit - moved tickCount below // Paper - Perf: Only tick item frames if players can see it + ItemStack itemStack = frame.getItem(); +- if (itemStack.getItem() instanceof MapItem) { +- MapId id = itemStack.get(DataComponents.MAP_ID); ++ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemStack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable ++ MapId id = frame.cachedMapId; // Paper - Perf: Cache map ids on item frames + MapItemSavedData data = MapItem.getSavedData(id, this.level); + if (data != null) { +- for (ServerPlayer player : this.level.players()) { + for (final net.minecraft.server.network.ServerPlayerConnection connection : this.trackedPlayers) { // Paper -+ final ServerPlayer serverPlayer = connection.getPlayer(); // Paper - savedData.tickCarriedBy(serverPlayer, item); - Packet updatePacket = savedData.getUpdatePacket(mapId, serverPlayer); - if (updatePacket != null) { ++ final ServerPlayer player = connection.getPlayer(); // Paper + data.tickCarriedBy(player, itemStack, frame); + Packet packet = data.getUpdatePacket(id, player); + if (packet != null) { @@ -136,7 +_,13 @@ } else { this.teleportDelay++; - Vec3 vec3 = this.entity.trackingPosition(); -- boolean flag1 = this.positionCodec.delta(vec3).lengthSqr() >= 7.6293945E-6F; + Vec3 currentPosition = this.entity.trackingPosition(); +- boolean positionChanged = this.positionCodec.delta(currentPosition).lengthSqr() >= 7.6293945E-6F; + // Paper start - reduce allocation of Vec3D here + Vec3 base = this.positionCodec.base; -+ double vec3_dx = vec3.x - base.x; -+ double vec3_dy = vec3.y - base.y; -+ double vec3_dz = vec3.z - base.z; -+ boolean flag1 = (vec3_dx * vec3_dx + vec3_dy * vec3_dy + vec3_dz * vec3_dz) >= 7.62939453125E-6D; ++ double vec3_dx = currentPosition.x - base.x; ++ double vec3_dy = currentPosition.y - base.y; ++ double vec3_dz = currentPosition.z - base.z; ++ boolean positionChanged = (vec3_dx * vec3_dx + vec3_dy * vec3_dy + vec3_dz * vec3_dz) >= 7.62939453125E-6D; + // Paper end - reduce allocation of Vec3D here Packet packet = null; - boolean flag2 = flag1 || this.tickCount % 60 == 0; - boolean flag3 = false; + boolean pos = positionChanged || this.tickCount % 60 == 0; + boolean sentPosition = false; @@ -218,6 +_,25 @@ this.tickCount++; @@ -86,7 +88,7 @@ this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundSetEntityMotionPacket(this.entity)); } @@ -269,7 +_,10 @@ - public void sendPairingData(ServerPlayer player, Consumer> consumer) { + public void sendPairingData(final ServerPlayer player, final Consumer> broadcast) { this.entity.updateDataBeforeSync(); if (this.entity.isRemoved()) { - LOGGER.warn("Fetching packet for removed entity {}", this.entity); @@ -96,25 +98,25 @@ + // CraftBukkit end } - Packet addEntityPacket = this.entity.getAddEntityPacket(this); + Packet packet = this.entity.getAddEntityPacket(this); @@ -280,6 +_,11 @@ if (this.entity instanceof LivingEntity livingEntity) { - Collection syncableAttributes = livingEntity.getAttributes().getSyncableAttributes(); + Collection attributes = livingEntity.getAttributes().getSyncableAttributes(); + // CraftBukkit start - If sending own attributes send scaled health instead of current maximum health + if (this.entity.getId() == player.getId()) { -+ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(syncableAttributes, false); ++ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(attributes, false); + } + // CraftBukkit end - if (!syncableAttributes.isEmpty()) { - consumer.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), syncableAttributes)); + if (!attributes.isEmpty()) { + broadcast.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributes)); } @@ -296,8 +_,9 @@ } - if (!list.isEmpty()) { -- consumer.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), list)); -+ consumer.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), list, true)); // Paper - data sanitization + if (!slots.isEmpty()) { +- broadcast.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), slots)); ++ broadcast.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), slots, true)); // Paper - data sanitization } + ((LivingEntity) this.entity).detectEquipmentUpdates(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending } @@ -122,13 +124,13 @@ if (!this.entity.getPassengers().isEmpty()) { @@ -344,6 +_,11 @@ if (this.entity instanceof LivingEntity) { - Set attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync(); - if (!attributesToSync.isEmpty()) { + Set attributes = ((LivingEntity)this.entity).getAttributes().getAttributesToSync(); + if (!attributes.isEmpty()) { + // CraftBukkit start - Send scaled max health + if (this.entity instanceof ServerPlayer serverPlayer) { -+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributesToSync, false); ++ serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributes, false); + } + // CraftBukkit end - this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync)); + this.synchronizer.sendToTrackingPlayersAndSelf(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributes)); } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 387abb411251..4ad6384f6eb1 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -1,22 +1,27 @@ --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -193,7 +_,7 @@ - final List players = Lists.newArrayList(); +@@ -194,7 +_,7 @@ + private final List players = Lists.newArrayList(); public final ServerChunkCache chunkSource; private final MinecraftServer server; - public final ServerLevelData serverLevelData; + public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type - final EntityTickList entityTickList = new EntityTickList(); + private final EntityTickList entityTickList = new EntityTickList(); private final ServerWaypointManager waypointManager; - private final EnvironmentAttributeSystem environmentAttributes; -@@ -221,25 +_,170 @@ - private final RandomSequences randomSequences; - final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this); + private EnvironmentAttributeSystem environmentAttributes; +@@ -221,24 +_,183 @@ + private final boolean tickTime; + private final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this); + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess levelStorageAccess; + public final UUID uuid; + public final net.minecraft.server.level.progress.LevelLoadListener levelLoadListener; ++ private final SavedDataStorage savedDataStorage; // Paper - save per-world data in level storage ++ private final net.minecraft.world.level.gamerules.GameRules gameRules; ++ private final WeatherData weatherData; ++ public final net.minecraft.world.level.timers.TimerQueue scheduledEvents; ++ public final net.minecraft.world.level.storage.LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings; + public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent + public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent + @@ -35,11 +40,11 @@ + // copied code from collision methods, so that we can guarantee that they won't load chunks (we don't override + // CollisionGetter methods for VoxelShapes) + // be more strict too, add a block (dumb plugins in move events?) -+ int minBlockX = Mth.floor(box.minX - 1.0E-7D) - 3; -+ int maxBlockX = Mth.floor(box.maxX + 1.0E-7D) + 3; ++ int minBlockX = Mth.floor(box.minX - 1.0E-7) - 3; ++ int maxBlockX = Mth.floor(box.maxX + 1.0E-7) + 3; + -+ int minBlockZ = Mth.floor(box.minZ - 1.0E-7D) - 3; -+ int maxBlockZ = Mth.floor(box.maxZ + 1.0E-7D) + 3; ++ int minBlockZ = Mth.floor(box.minZ - 1.0E-7) - 3; ++ int maxBlockZ = Mth.floor(box.maxZ + 1.0E-7) + 3; + + int minChunkX = minBlockX >> 4; + int maxChunkX = maxBlockX >> 4; @@ -68,11 +73,11 @@ + }); + return; + } -+ int minBlockX = Mth.floor(box.minX - 1.0E-7D) - 3; -+ int minBlockZ = Mth.floor(box.minZ - 1.0E-7D) - 3; ++ int minBlockX = Mth.floor(box.minX - 1.0E-7) - 3; ++ int minBlockZ = Mth.floor(box.minZ - 1.0E-7) - 3; + -+ int maxBlockX = Mth.floor(box.maxX + 1.0E-7D) + 3; -+ int maxBlockZ = Mth.floor(box.maxZ + 1.0E-7D) + 3; ++ int maxBlockX = Mth.floor(box.maxX + 1.0E-7) + 3; ++ int maxBlockZ = Mth.floor(box.maxZ + 1.0E-7) + 3; + + int minChunkX = minBlockX >> 4; + int minChunkZ = minBlockZ >> 4; @@ -95,7 +100,7 @@ + + java.util.function.Consumer consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> { + if (chunk != null) { -+ int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel()); ++ int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().pack()).getTicketLevel()); + ret.add(chunk); + ticketLevels.add(ticketLevel); + chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel); @@ -135,88 +140,111 @@ + // Paper end - optimise getPlayerByUUID + public ServerLevel( - MinecraftServer server, - Executor dispatcher, - LevelStorageSource.LevelStorageAccess levelStorageAccess, -- ServerLevelData serverLevelData, -+ net.minecraft.world.level.storage.PrimaryLevelData serverLevelData, // CraftBukkit - ResourceKey dimension, - LevelStem levelStem, - boolean isDebug, - long biomeZoomSeed, - List customSpawners, - boolean tickTime, -- @Nullable RandomSequences randomSequences -+ @Nullable RandomSequences randomSequences, -+ org.bukkit.World.Environment env, // CraftBukkit + final MinecraftServer server, + final Executor executor, + final LevelStorageSource.LevelStorageAccess levelStorage, +- final ServerLevelData levelData, ++ final net.minecraft.world.level.storage.LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings, // CraftBukkit + final ResourceKey dimension, + final LevelStem levelStem, + final boolean isDebug, + final long biomeZoomSeed, + final List customSpawners, + final boolean tickTime ++ , org.bukkit.World.Environment env, // CraftBukkit + org.bukkit.generator.ChunkGenerator gen, // CraftBukkit -+ org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit ++ org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit ++ SavedDataStorage savedDataStorage // Paper - pass SavedDataStorage ) { -- super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates()); +- super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates()); + // CraftBukkit start -+ super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules()))); // Paper - create paper world configs -+ this.levelStorageAccess = levelStorageAccess; ++ final var levelData = (net.minecraft.world.level.storage.PrimaryLevelData) worldDataAndGenSettings.data(); ++ final GameRules gameRules = new GameRules(levelData.enabledFeatures(), savedDataStorage.computeIfAbsent(net.minecraft.world.level.gamerules.GameRuleMap.TYPE)); ++ this.gameRules = gameRules; ++ super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorage.levelDirectory.path(), levelData.getLevelName(), dimension.identifier(), spigotConfig, server.registryAccess(), gameRules))); // Paper - create paper world configs ++ this.savedDataStorage = savedDataStorage; // Paper - save per-world data in level storage ++ this.weatherData = savedDataStorage.computeIfAbsent(WeatherData.TYPE); ++ this.weatherData.setLevel(this); ++ this.levelStorageAccess = levelStorage; + this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getOrCreate(levelStorageAccess.levelDirectory.path().toFile()); + this.levelLoadListener = new net.minecraft.server.level.progress.LoggingLevelLoadListener(false, this); ++ this.worldDataAndGenSettings = worldDataAndGenSettings; ++ this.scheduledEvents = savedDataStorage.computeIfAbsent(net.minecraft.world.level.timers.TimerQueue.TYPE); + // CraftBukkit end this.tickTime = tickTime; this.server = server; this.customSpawners = customSpawners; - this.serverLevelData = serverLevelData; - ChunkGenerator chunkGenerator = levelStem.generator(); + this.serverLevelData = levelData; + ChunkGenerator generator = levelStem.generator(); + // CraftBukkit start + this.serverLevelData.setWorld(this); + + if (biomeProvider != null) { -+ net.minecraft.world.level.biome.BiomeSource biomeSource = new org.bukkit.craftbukkit.generator.CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME), chunkGenerator.getBiomeSource()); // Paper - add vanillaBiomeProvider -+ if (chunkGenerator instanceof net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator noiseBased) { -+ chunkGenerator = new net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator(biomeSource, noiseBased.settings); -+ } else if (chunkGenerator instanceof net.minecraft.world.level.levelgen.FlatLevelSource flatLevel) { -+ chunkGenerator = new net.minecraft.world.level.levelgen.FlatLevelSource(flatLevel.settings(), biomeSource); ++ net.minecraft.world.level.biome.BiomeSource biomeSource = new org.bukkit.craftbukkit.generator.CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME), generator.getBiomeSource()); // Paper - add vanillaBiomeProvider ++ if (generator instanceof net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator noiseBased) { ++ generator = new net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator(biomeSource, noiseBased.settings); ++ } else if (generator instanceof net.minecraft.world.level.levelgen.FlatLevelSource flatLevel) { ++ generator = new net.minecraft.world.level.levelgen.FlatLevelSource(flatLevel.settings(), biomeSource); + } + } + + if (gen != null) { -+ chunkGenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkGenerator, gen); ++ generator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, generator, gen); + } + // CraftBukkit end - boolean flag = server.forceSynchronousWrites(); + boolean syncWrites = server.forceSynchronousWrites(); DataFixer fixerUpper = server.getFixerUpper(); - EntityPersistentStorage entityPersistentStorage = new EntityStorage( -@@ -261,8 +_,8 @@ + EntityPersistentStorage entityStorage = new EntityStorage( +@@ -260,8 +_,8 @@ server.getStructureManager(), - dispatcher, - chunkGenerator, + executor, + generator, - server.getPlayerList().getViewDistance(), - server.getPlayerList().getSimulationDistance(), + this.spigotConfig.viewDistance, // Spigot + this.spigotConfig.simulationDistance, // Spigot - flag, + syncWrites, this.entityManager::updateChunkStatus, () -> server.overworld().getDataStorage() -@@ -283,7 +_,7 @@ +@@ -269,7 +_,7 @@ + this.chunkSource.getGeneratorState().ensureStructuresGenerated(); + this.portalForcer = new PortalForcer(this); + if (this.canHaveWeather()) { +- this.prepareWeather(server.getWeatherData()); ++ this.prepareWeather(this.weatherData); // Paper - per-level WeatherData + } + + this.raids = this.getDataStorage().computeIfAbsent(Raids.TYPE); +@@ -277,14 +_,14 @@ + levelData.setGameType(server.getDefaultGameType()); + } + +- WorldGenSettings worldGenSettings = server.getWorldGenSettings(); ++ WorldGenSettings worldGenSettings = worldDataAndGenSettings.genSettings(); // Paper - use world's gen settings + WorldOptions options = worldGenSettings.options(); + long seed = options.seed(); + this.structureCheck = new StructureCheck( this.chunkSource.chunkScanner(), this.registryAccess(), server.getStructureManager(), - dimension, + getTypeKey(), // Paper - Fix missing CB diff - chunkGenerator, + generator, this.chunkSource.randomState(), this, -@@ -291,9 +_,9 @@ +@@ -292,8 +_,9 @@ seed, fixerUpper ); -- this.structureManager = new StructureManager(this, server.getWorldData().worldGenOptions(), this.structureCheck); -- if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) { -- this.dragonFight = new EndDragonFight(this, seed, server.getWorldData().endDragonFightData()); -+ this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), this.structureCheck); // CraftBukkit -+ if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END -+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit - } else { - this.dragonFight = null; +- this.structureManager = new StructureManager(this, options, this.structureCheck); +- if (this.dimensionType().hasEnderDragonFight()) { ++ this.structureManager = new StructureManager(this, worldDataAndGenSettings.genSettings().options(), this.structureCheck); // CraftBukkit ++ if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(net.minecraft.world.level.dimension.BuiltinDimensionTypes.END) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END ++ // this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit // TODO - snapshot + this.dragonFight = this.getDataStorage().computeIfAbsent(EnderDragonFight.TYPE); + this.dragonFight.init(this, seed, BlockPos.ZERO); } -@@ -304,7 +_,15 @@ +@@ -303,7 +_,15 @@ this.waypointManager = new ServerWaypointManager(); this.environmentAttributes = EnvironmentAttributeSystem.builder().addDefaultLayers(this).build(); this.updateSkyBrightness(); @@ -233,175 +261,170 @@ @Deprecated @VisibleForTesting -@@ -316,8 +_,8 @@ - this.serverLevelData.setClearWeatherTime(clearTime); - this.serverLevelData.setRainTime(weatherTime); - this.serverLevelData.setThunderTime(weatherTime); -- this.serverLevelData.setRaining(isRaining); -- this.serverLevelData.setThundering(isThundering); -+ this.serverLevelData.setRaining(isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents -+ this.serverLevelData.setThundering(isThundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.COMMAND); // Paper - Add cause to Weather/ThunderChangeEvents - } - - @Override -@@ -349,12 +_,25 @@ - - int i = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE); - if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { -+ // Paper start - create time skip event - move up calculations -+ final long newDayTime = this.levelData.getDayTime() + 24000L; -+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent( -+ this.getWorld(), -+ org.bukkit.event.world.TimeSkipEvent.SkipReason.NIGHT_SKIP, -+ (newDayTime - newDayTime % 24000L) - this.getDayTime() -+ ); -+ // Paper end - create time skip event - move up calculations - if (this.getGameRules().get(GameRules.ADVANCE_TIME)) { -- long l = this.levelData.getDayTime() + 24000L; -- this.setDayTime(l - l % 24000L); -+ // Paper start - call time skip event if gamerule is enabled -+ // long l = this.levelData.getDayTime() + 24000L; // Paper - diff on change to above - newDayTime -+ // this.setDayTime(l - l % 24000L); // Paper - diff on change to above - event param +@@ -354,11 +_,24 @@ + int percentage = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE); + if (this.sleepStatus.areEnoughSleeping(percentage) && this.sleepStatus.areEnoughDeepSleeping(percentage, this.players)) { + Optional> defaultClock = this.dimensionType().defaultClock(); ++ org.bukkit.event.world.TimeSkipEvent event = null; // Paper - time skip event + if (this.getGameRules().get(GameRules.ADVANCE_TIME) && defaultClock.isPresent()) { +- this.server.clockManager().moveToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP); ++ // Paper start - time skip event ++ long currentTime = this.server.clockManager().getTotalTicks(defaultClock.get()); ++ long delta = this.server.clockManager().getTotalTicksToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP).orElse(0L) - currentTime; ++ event = new org.bukkit.event.world.TimeSkipEvent( ++ this.getWorld(), ++ org.bukkit.event.world.TimeSkipEvent.SkipReason.NIGHT_SKIP, ++ delta ++ ); ++ + if (event.callEvent()) { -+ this.setDayTime(this.getDayTime() + event.getSkipAmount()); ++ this.server.clockManager().setTotalTicks(defaultClock.get(), currentTime + event.getSkipAmount()); // TODO - snapshot - per world time + } -+ // Paper end - call time skip event if gamerule is enabled ++ // Paper end - time skip event } - this.wakeUpAllPlayers(); -+ if (!event.isCancelled()) this.wakeUpAllPlayers(); // Paper - only wake up players if time skip event is not cancelled ++ if (event == null || !event.isCancelled()) this.wakeUpAllPlayers(); // Paper - time skip event - only wake up players if time skip event is not cancelled if (this.getGameRules().get(GameRules.ADVANCE_WEATHER) && this.isRaining()) { this.resetWeatherCycle(); } -@@ -369,9 +_,9 @@ - if (!this.isDebug() && runsNormally) { - long l = this.getGameTime(); - profilerFiller.push("blockTicks"); -- this.blockTicks.tick(l, 65536, this::tickBlock); -+ this.blockTicks.tick(l, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks - profilerFiller.popPush("fluidTicks"); -- this.fluidTicks.tick(l, 65536, this::tickFluid); -+ this.fluidTicks.tick(l, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks - profilerFiller.pop(); +@@ -373,9 +_,9 @@ + if (!this.isDebug() && runs) { + long tick = this.getGameTime(); + profiler.push("blockTicks"); +- this.blockTicks.tick(tick, 65536, this::tickBlock); ++ this.blockTicks.tick(tick, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks + profiler.popPush("fluidTicks"); +- this.fluidTicks.tick(tick, 65536, this::tickFluid); ++ this.fluidTicks.tick(tick, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks + profiler.pop(); } -@@ -389,7 +_,7 @@ +@@ -393,7 +_,7 @@ this.handlingTick = false; - profilerFiller.pop(); -- boolean hasActiveTickets = this.chunkSource.hasActiveTickets(); -+ boolean hasActiveTickets = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || this.chunkSource.hasActiveTickets(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this - if (hasActiveTickets) { + profiler.pop(); +- boolean isActive = this.chunkSource.hasActiveTickets(); ++ boolean isActive = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || this.chunkSource.hasActiveTickets(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this + if (isActive) { this.resetEmptyTime(); } -@@ -498,11 +_,13 @@ - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("iceandsnow"); +@@ -468,7 +_,7 @@ + long time = this.levelData.getGameTime() + 1L; + this.serverLevelData.setGameTime(time); + Profiler.get().push("scheduledFunctions"); +- this.server.getScheduledEvents().tick(this.server, time); ++ this.scheduledEvents.tick(this.server, time); // Paper - per-level scheduledEvents + Profiler.get().pop(); + } + } +@@ -491,11 +_,13 @@ + ProfilerFiller profiler = Profiler.get(); + profiler.push("iceandsnow"); + if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow - for (int i = 0; i < randomTickSpeed; i++) { + for (int i = 0; i < tickSpeed; i++) { if (this.random.nextInt(48) == 0) { - this.tickPrecipitation(this.getBlockRandomPos(minBlockX, 0, minBlockZ, 15)); + this.tickPrecipitation(this.getBlockRandomPos(minX, 0, minZ, 15)); } } + } // Paper - Option to disable ice and snow - profilerFiller.popPush("tickBlocks"); - if (randomTickSpeed > 0) { -@@ -545,12 +_,12 @@ - int minBlockZ = pos.getMinBlockZ(); - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("thunder"); -- if (isRaining && this.isThundering() && this.random.nextInt(100000) == 0) { -+ if (!this.paperConfig().environment.disableThunder && isRaining && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder - BlockPos blockPos = this.findLightningTargetAround(this.getBlockRandomPos(minBlockX, 0, minBlockZ, 15)); - if (this.isRainingAt(blockPos)) { - DifficultyInstance currentDifficultyAt = this.getCurrentDifficultyAt(blockPos); - boolean flag = this.getGameRules().get(GameRules.SPAWN_MOBS) -- && this.random.nextDouble() < currentDifficultyAt.getEffectiveDifficulty() * 0.01 -+ && this.random.nextDouble() < currentDifficultyAt.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01) // Paper - Configurable spawn chances for skeleton horses - && !this.getBlockState(blockPos.below()).is(BlockTags.LIGHTNING_RODS); - if (flag) { - SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT); -@@ -558,7 +_,7 @@ - skeletonHorse.setTrap(true); - skeletonHorse.setAge(0); - skeletonHorse.setPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()); -- this.addFreshEntity(skeletonHorse); -+ this.addFreshEntity(skeletonHorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit + profiler.popPush("tickBlocks"); + if (tickSpeed > 0) { +@@ -536,12 +_,12 @@ + int minZ = chunkPos.getMinBlockZ(); + ProfilerFiller profiler = Profiler.get(); + profiler.push("thunder"); +- if (raining && this.isThundering() && this.random.nextInt(100000) == 0) { ++ if (!this.paperConfig().environment.disableThunder && raining && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder + BlockPos pos = this.findLightningTargetAround(this.getBlockRandomPos(minX, 0, minZ, 15)); + if (this.isRainingAt(pos)) { + DifficultyInstance difficulty = this.getCurrentDifficultyAt(pos); + boolean isTrap = this.getGameRules().get(GameRules.SPAWN_MOBS) +- && this.random.nextDouble() < difficulty.getEffectiveDifficulty() * 0.01 ++ && this.random.nextDouble() < difficulty.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01) // Paper - Configurable spawn chances for skeleton horses + && !this.getBlockState(pos.below()).is(BlockTags.LIGHTNING_RODS); + if (isTrap) { + SkeletonHorse horse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT); +@@ -549,7 +_,7 @@ + horse.setTrap(true); + horse.setAge(0); + horse.setPos(pos.getX(), pos.getY(), pos.getZ()); +- this.addFreshEntity(horse); ++ this.addFreshEntity(horse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit } } -@@ -566,7 +_,7 @@ - if (lightningBolt != null) { - lightningBolt.snapTo(Vec3.atBottomCenterOf(blockPos)); - lightningBolt.setVisualOnly(flag); -- this.addFreshEntity(lightningBolt); -+ this.strikeLightning(lightningBolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit +@@ -557,7 +_,7 @@ + if (bolt != null) { + bolt.snapTo(Vec3.atBottomCenterOf(pos)); + bolt.setVisualOnly(isTrap); +- this.addFreshEntity(bolt); ++ this.strikeLightning(bolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit } } } -@@ -580,7 +_,7 @@ - BlockPos blockPos = heightmapPos.below(); - Biome biome = this.getBiome(heightmapPos).value(); - if (biome.shouldFreeze(this, blockPos)) { -- this.setBlockAndUpdate(blockPos, Blocks.ICE.defaultBlockState()); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockPos, Blocks.ICE.defaultBlockState(), Block.UPDATE_ALL, null); // CraftBukkit +@@ -571,7 +_,7 @@ + BlockPos belowPos = topPos.below(); + Biome biome = this.getBiome(topPos).value(); + if (biome.shouldFreeze(this, belowPos)) { +- this.setBlockAndUpdate(belowPos, Blocks.ICE.defaultBlockState()); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, belowPos, Blocks.ICE.defaultBlockState(), Block.UPDATE_ALL, null); // CraftBukkit } if (this.isRaining()) { -@@ -592,10 +_,10 @@ - if (layersValue < Math.min(i, 8)) { - BlockState blockState1 = blockState.setValue(SnowLayerBlock.LAYERS, layersValue + 1); - Block.pushEntitiesUp(blockState, blockState1, this, heightmapPos); -- this.setBlockAndUpdate(heightmapPos, blockState1); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, blockState1, Block.UPDATE_ALL, null); // CraftBukkit +@@ -583,10 +_,10 @@ + if (currentLayers < Math.min(maxHeight, 8)) { + BlockState newState = state.setValue(SnowLayerBlock.LAYERS, currentLayers + 1); + Block.pushEntitiesUp(state, newState, this, topPos); +- this.setBlockAndUpdate(topPos, newState); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, topPos, newState, Block.UPDATE_ALL, null); // CraftBukkit } } else { -- this.setBlockAndUpdate(heightmapPos, Blocks.SNOW.defaultBlockState()); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, heightmapPos, Blocks.SNOW.defaultBlockState(), Block.UPDATE_ALL, null); // CraftBukkit +- this.setBlockAndUpdate(topPos, Blocks.SNOW.defaultBlockState()); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, topPos, Blocks.SNOW.defaultBlockState(), Block.UPDATE_ALL, null); // CraftBukkit } } -@@ -620,6 +_,12 @@ +@@ -611,16 +_,24 @@ } - protected BlockPos findLightningTargetAround(BlockPos pos) { + protected BlockPos findLightningTargetAround(final BlockPos pos) { + // Paper start - Add methods to find targets for lightning strikes + return this.findLightningTargetAround(pos, false); + } + -+ public BlockPos findLightningTargetAround(BlockPos pos, boolean returnNullWhenNoTarget) { ++ @org.jetbrains.annotations.Contract("_, false -> !null") ++ public @Nullable BlockPos findLightningTargetAround(final BlockPos pos, boolean returnNullWhenNoTarget) { + // Paper end - Add methods to find targets for lightning strikes - BlockPos heightmapPos = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); - Optional optional = this.findLightningRod(heightmapPos); - if (optional.isPresent()) { -@@ -627,11 +_,12 @@ + BlockPos center = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); + Optional lightningRodTarget = this.findLightningRod(center); + if (lightningRodTarget.isPresent()) { + return lightningRodTarget.get(); } else { - AABB aabb = AABB.encapsulatingFullBlocks(heightmapPos, heightmapPos.atY(this.getMaxY() + 1)).inflate(3.0); - List entitiesOfClass = this.getEntitiesOfClass( -- LivingEntity.class, aabb, entity -> entity.isAlive() && this.canSeeSky(entity.blockPosition()) -+ LivingEntity.class, aabb, entity -> entity.isAlive() && this.canSeeSky(entity.blockPosition()) && !entity.isSpectator() // Paper - Fix lightning being able to hit spectators (MC-262422) - ); - if (!entitiesOfClass.isEmpty()) { - return entitiesOfClass.get(this.random.nextInt(entitiesOfClass.size())).blockPosition(); + AABB search = AABB.encapsulatingFullBlocks(center, center.atY(this.getMaxY() + 1)).inflate(3.0); +- List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition())); ++ List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition()) && !input.isSpectator()); // Paper - Fix lightning being able to hit spectators (MC-262422) + if (!entities.isEmpty()) { + return entities.get(this.random.nextInt(entities.size())).blockPosition(); } else { + if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes - if (heightmapPos.getY() == this.getMinY() - 1) { - heightmapPos = heightmapPos.above(2); + if (center.getY() == this.getMinY() - 1) { + center = center.above(2); } -@@ -740,8 +_,8 @@ - this.serverLevelData.setThunderTime(thunderTime); - this.serverLevelData.setRainTime(rainTime); - this.serverLevelData.setClearWeatherTime(clearWeatherTime); -- this.serverLevelData.setThundering(isThundering); -- this.serverLevelData.setRaining(isRaining1); -+ this.serverLevelData.setThundering(isThundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents -+ this.serverLevelData.setRaining(isRaining1, org.bukkit.event.weather.WeatherChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents +@@ -739,8 +_,8 @@ + weatherData.setThunderTime(thunderTime); + weatherData.setRainTime(rainTime); + weatherData.setClearWeatherTime(clearWeatherTime); +- weatherData.setThundering(thundering); +- weatherData.setRaining(raining); ++ weatherData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents ++ weatherData.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.NATURAL); // Paper - Add cause to Weather/ThunderChangeEvents } this.oThunderLevel = this.thunderLevel; -@@ -762,6 +_,7 @@ +@@ -761,6 +_,7 @@ this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F); } @@ -409,7 +432,7 @@ if (this.oRainLevel != this.rainLevel) { this.server .getPlayerList() -@@ -784,14 +_,47 @@ +@@ -783,15 +_,48 @@ this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel)); this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel)); } @@ -420,11 +443,11 @@ + } + } + -+ if (isRaining != this.isRaining()) { ++ if (wasRaining != this.isRaining()) { + // Only send weather packets to those affected + for (ServerPlayer player : this.players) { + if (player.level() == this) { -+ player.setPlayerWeather((!isRaining ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.WeatherType.CLEAR), false); ++ player.setPlayerWeather((!wasRaining ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.WeatherType.CLEAR), false); + } + } + } @@ -438,24 +461,25 @@ @VisibleForTesting public void resetWeatherCycle() { -- this.serverLevelData.setRainTime(0); -- this.serverLevelData.setRaining(false); -- this.serverLevelData.setThunderTime(0); -- this.serverLevelData.setThundering(false); + WeatherData weatherData = this.getWeatherData(); +- weatherData.setRainTime(0); +- weatherData.setRaining(false); +- weatherData.setThunderTime(0); +- weatherData.setThundering(false); + // CraftBukkit start -+ this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents ++ weatherData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. + // Not that everyone ever manages to get the whole server to sleep at the same time.... -+ if (!this.serverLevelData.isRaining()) { -+ this.serverLevelData.setRainTime(0); ++ if (!weatherData.isRaining()) { ++ weatherData.setRainTime(0); + } + // CraftBukkit end -+ this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents ++ weatherData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // CraftBukkit start + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. + // Not that everyone ever manages to get the whole server to sleep at the same time.... -+ if (!this.serverLevelData.isThundering()) { -+ this.serverLevelData.setThunderTime(0); ++ if (!weatherData.isThundering()) { ++ weatherData.setThunderTime(0); + } + // CraftBukkit end } @@ -477,7 +501,7 @@ + } + // Paper end - log detailed entity tick information + - public void tickNonPassenger(Entity entity) { + public void tickNonPassenger(final Entity entity) { + // Paper start - log detailed entity tick information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); + try { @@ -486,17 +510,17 @@ + } + // Paper end - log detailed entity tick information entity.setOldPosAndRot(); - ProfilerFiller profilerFiller = Profiler.get(); + ProfilerFiller profiler = Profiler.get(); entity.tickCount++; + entity.totalEntityAge++; // Paper - age-like counter for all entities - profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()); - profilerFiller.incrementCounter("tickNonPassenger"); + profiler.push(entity.typeHolder()::getRegisteredName); + profiler.incrementCounter("tickNonPassenger"); entity.tick(); + entity.postTick(); // CraftBukkit - profilerFiller.pop(); + profiler.pop(); - for (Entity entity1 : entity.getPassengers()) { - this.tickPassenger(entity, entity1); + for (Entity passenger : entity.getPassengers()) { + this.tickPassenger(entity, passenger); } + // Paper start - log detailed entity tick information + } finally { @@ -507,75 +531,77 @@ + // Paper end - log detailed entity tick information } - private void tickPassenger(Entity ridingEntity, Entity passengerEntity) { + private void tickPassenger(final Entity vehicle, final Entity entity) { @@ -833,10 +_,12 @@ - } else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) { - passengerEntity.setOldPosAndRot(); - passengerEntity.tickCount++; -+ passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString()); - profilerFiller.incrementCounter("tickPassenger"); - passengerEntity.rideTick(); -+ passengerEntity.postTick(); // CraftBukkit - profilerFiller.pop(); - - for (Entity entity : passengerEntity.getPassengers()) { + } else if (entity instanceof Player || this.entityTickList.contains(entity)) { + entity.setOldPosAndRot(); + entity.tickCount++; ++ entity.totalEntityAge++; // Paper - age-like counter for all entities + ProfilerFiller profiler = Profiler.get(); + profiler.push(entity.typeHolder()::getRegisteredName); + profiler.incrementCounter("tickPassenger"); + entity.rideTick(); ++ entity.postTick(); // CraftBukkit + profiler.pop(); + + for (Entity passenger : entity.getPassengers()) { @@ -867,6 +_,7 @@ - public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) { + public void save(final @Nullable ProgressListener progressListener, final boolean flush, final boolean noSave) { ServerChunkCache chunkSource = this.getChunkSource(); - if (!skipSave) { -+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit - if (progress != null) { - progress.progressStartNoAbort(Component.translatable("menu.savingLevel")); + if (!noSave) { ++ new org.bukkit.event.world.WorldSaveEvent(this.getWorld()).callEvent(); // CraftBukkit + if (progressListener != null) { + progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); } -@@ -883,11 +_,18 @@ +@@ -883,9 +_,21 @@ this.entityManager.autoSave(); } } + + // CraftBukkit start - moved from MinecraftServer#saveAllChunks -+ ServerLevel serverLevel1 = this; -+ -+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess())); -+ this.levelStorageAccess.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); -+ // CraftBukkit end ++ com.mojang.authlib.GameProfile singleplayerProfile = this.server.getSingleplayerProfile(); ++ this.levelStorageAccess.saveDataTag(this.worldDataAndGenSettings.data(), singleplayerProfile == null ? null : singleplayerProfile.id()); ++ // CraftBukkit end - moved from MinecraftServer#saveAllChunks } - private void saveLevelData(boolean join) { - if (this.dragonFight != null) { -- this.server.getWorldData().setEndDragonFightData(this.dragonFight.saveData()); -+ this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit - } - - DimensionDataStorage dataStorage = this.getChunkSource().getDataStorage(); -@@ -951,18 +_,40 @@ + private void saveLevelData(final boolean sync) { ++ // Paper start - save per-world data in level storage ++ if (sync) { ++ this.savedDataStorage.saveAndJoin(); ++ } else { ++ this.savedDataStorage.scheduleSave(); ++ } ++ // Paper end - save per-world data in level storage + SavedDataStorage savedDataStorage = this.getChunkSource().getDataStorage(); + if (sync) { + savedDataStorage.saveAndJoin(); +@@ -949,18 +_,40 @@ @Override - public boolean addFreshEntity(Entity entity) { + public boolean addFreshEntity(final Entity entity) { - return this.addEntity(entity); + // CraftBukkit start + return this.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + @Override -+ public boolean addFreshEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { ++ public boolean addFreshEntity(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { + return this.addEntity(entity, reason); + // CraftBukkit end } - public boolean addWithUUID(Entity entity) { + public boolean addWithUUID(final Entity entity) { - return this.addEntity(entity); + // CraftBukkit start + return this.addWithUUID(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + -+ public boolean addWithUUID(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { ++ public boolean addWithUUID(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { + return this.addEntity(entity, reason); + // CraftBukkit end } - public void addDuringTeleport(Entity entity) { + public void addDuringTeleport(final Entity entity) { + // CraftBukkit start + // SPIGOT-6415: Don't call spawn event for entities which travel trough worlds, + // since it is only an implementation detail, that a new entity is created when @@ -583,23 +609,23 @@ + this.addDuringTeleport(entity, null); + } + -+ public void addDuringTeleport(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { ++ public void addDuringTeleport(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason reason) { + // CraftBukkit end - if (entity instanceof ServerPlayer serverPlayer) { - this.addPlayer(serverPlayer); + if (entity instanceof ServerPlayer player) { + this.addPlayer(player); } else { - this.addEntity(entity); + this.addEntity(entity, reason); // CraftBukkit } } -@@ -985,41 +_,120 @@ +@@ -983,42 +_,121 @@ this.entityManager.addNewEntity(player); } -- private boolean addEntity(Entity entity) { +- private boolean addEntity(final Entity entity) { + // CraftBukkit start -+ private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason spawnReason) { ++ private boolean addEntity(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.@Nullable SpawnReason spawnReason) { + org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot + entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process + // Paper start - extra debug info @@ -610,14 +636,14 @@ + // Paper end - extra debug info + if (entity.spawnReason == null) entity.spawnReason = spawnReason; // Paper - Entity#getEntitySpawnReason if (entity.isRemoved()) { -- LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType())); -+ // LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType())); // CraftBukkit - remove warning +- LOGGER.warn("Tried to add entity {} but it was marked as removed already", entity.typeHolder().getRegisteredName()); ++ // LOGGER.warn("Tried to add entity {} but it was marked as removed already", entity.typeHolder().getRegisteredName()); // CraftBukkit - remove warning return false; } else { -+ if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added ++ if (entity instanceof net.minecraft.world.entity.item.ItemEntity item && item.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added + // Paper start - capture all item additions to the world -+ if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { -+ captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); ++ if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity item) { ++ captureDrops.add(item); + return true; + } + // Paper end - capture all item additions to the world @@ -631,12 +657,12 @@ } } - public boolean tryAddFreshEntityWithPassengers(Entity entity) { + public boolean tryAddFreshEntityWithPassengers(final Entity entity) { + // CraftBukkit start + return this.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + -+ public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ public boolean tryAddFreshEntityWithPassengers(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { + // CraftBukkit end if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.entityManager::isLoaded)) { return false; @@ -647,9 +673,9 @@ } } - public void unload(LevelChunk chunk) { + public void unload(final LevelChunk levelChunk) { + // Spigot start -+ for (net.minecraft.world.level.block.entity.BlockEntity blockEntity : chunk.getBlockEntities().values()) { ++ for (net.minecraft.world.level.block.entity.BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { + if (blockEntity instanceof net.minecraft.world.Container) { + // Paper start - this area looks like it can load chunks, change the behavior + // chests for example can apply physics to the world @@ -661,12 +687,12 @@ + } + } + // Spigot end - chunk.clearAllBlockEntities(); - chunk.unregisterTickContainerFromLevel(this); - this.debugSynchronizers.dropChunk(chunk.getPos()); + levelChunk.clearAllBlockEntities(); + levelChunk.unregisterTickContainerFromLevel(this); + this.debugSynchronizers.dropChunk(levelChunk.getPos()); } - public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) { + public void removePlayerImmediately(final ServerPlayer player, final Entity.RemovalReason reason) { - player.remove(reason); - } + player.remove(reason, null); // CraftBukkit - add Bukkit remove cause @@ -689,10 +715,10 @@ + // CraftBukkit end @Override - public void destroyBlockProgress(int breakerId, BlockPos pos, int progress) { + public void destroyBlockProgress(final int id, final BlockPos blockPos, final int progress) { + // CraftBukkit start + Player breakerPlayer = null; -+ Entity entity = this.getEntity(breakerId); ++ Entity entity = this.getEntity(id); + if (entity instanceof Player) breakerPlayer = (Player) entity; + // CraftBukkit end + @@ -701,25 +727,26 @@ + // Hence, do not call the event. + if (entity != null) { + float progressFloat = Mth.clamp(progress, 0, 10) / 10.0f; -+ org.bukkit.craftbukkit.block.CraftBlock bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this, pos); ++ org.bukkit.craftbukkit.block.CraftBlock bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this, blockPos); + new io.papermc.paper.event.block.BlockBreakProgressUpdateEvent(bukkitBlock, progressFloat, entity.getBukkitEntity()) + .callEvent(); + } + // Paper end - Add BlockBreakProgressUpdateEvent - for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) { - if (serverPlayer.level() == this && serverPlayer.getId() != breakerId) { - double d = pos.getX() - serverPlayer.getX(); - double d1 = pos.getY() - serverPlayer.getY(); - double d2 = pos.getZ() - serverPlayer.getZ(); -+ // CraftBukkit start -+ if (breakerPlayer != null && !serverPlayer.getBukkitEntity().canSee(breakerPlayer.getBukkitEntity())) { -+ continue; -+ } -+ // CraftBukkit end - if (d * d + d1 * d1 + d2 * d2 < 1024.0) { - serverPlayer.connection.send(new ClientboundBlockDestructionPacket(breakerId, pos, progress)); + for (ServerPlayer player : this.server.getPlayerList().getPlayers()) { + if (player.level() == this && player.getId() != id) { + double xd = blockPos.getX() - player.getX(); + double yd = blockPos.getY() - player.getY(); + double zd = blockPos.getZ() - player.getZ(); + if (xd * xd + yd * yd + zd * zd < 1024.0) { ++ // CraftBukkit start ++ if (breakerPlayer != null && !player.getBukkitEntity().canSee(breakerPlayer.getBukkitEntity())) { ++ continue; ++ } ++ // CraftBukkit end + player.connection.send(new ClientboundBlockDestructionPacket(id, blockPos, progress)); } -@@ -1094,7 +_,7 @@ + } +@@ -1106,7 +_,7 @@ pos.getX(), pos.getY(), pos.getZ(), @@ -728,33 +755,33 @@ this.dimension(), new ClientboundLevelEventPacket(type, pos, data, false) ); -@@ -1106,6 +_,11 @@ +@@ -1118,6 +_,11 @@ @Override - public void gameEvent(Holder gameEvent, Vec3 pos, GameEvent.Context context) { + public void gameEvent(final Holder gameEvent, final Vec3 position, final GameEvent.Context context) { + // Paper start - Prevent GameEvents being fired from unloaded chunks -+ if (this.getChunkIfLoadedImmediately((Mth.floor(pos.x) >> 4), (Mth.floor(pos.z) >> 4)) == null) { ++ if (this.getChunkIfLoadedImmediately((Mth.floor(position.x) >> 4), (Mth.floor(position.z) >> 4)) == null) { + return; + } + // Paper end - Prevent GameEvents being fired from unloaded chunks - this.gameEventDispatcher.post(gameEvent, pos, context); + this.gameEventDispatcher.post(gameEvent, position, context); } -@@ -1118,17 +_,28 @@ +@@ -1130,17 +_,28 @@ this.getChunkSource().blockChanged(pos); this.pathTypesByPosCache.invalidate(pos); + if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates - VoxelShape collisionShape = oldState.getCollisionShape(this, pos); - VoxelShape collisionShape1 = newState.getCollisionShape(this, pos); - if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) { - List list = new ObjectArrayList<>(); + VoxelShape oldShape = old.getCollisionShape(this, pos); + VoxelShape newShape = current.getCollisionShape(this, pos); + if (Shapes.joinIsNotEmpty(oldShape, newShape, BooleanOp.NOT_SAME)) { + List navigationsToUpdate = new ObjectArrayList<>(); + try { // Paper - catch CME see below why - for (Mob mob : this.navigatingMobs) { - PathNavigation navigation = mob.getNavigation(); - if (navigation.shouldRecomputePath(pos)) { - list.add(navigation); + for (Mob navigatingMob : this.navigatingMobs) { + PathNavigation pathNavigation = navigatingMob.getNavigation(); + if (pathNavigation.shouldRecomputePath(pos)) { + navigationsToUpdate.add(pathNavigation); } } + // Paper start - catch CME see below why @@ -762,14 +789,14 @@ + // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register + // In this case we just run the update again across all the iterators as the chunk will then be loaded + // As this is a relative edge case it is much faster than copying navigators (on either read or write) -+ this.sendBlockUpdated(pos, oldState, newState, flags); ++ this.sendBlockUpdated(pos, old, current, updateFlags); + return; + } + // Paper end - catch CME see below why try { this.isUpdatingNavigations = true; -@@ -1140,15 +_,23 @@ +@@ -1152,15 +_,23 @@ this.isUpdatingNavigations = false; } } @@ -777,107 +804,109 @@ } @Override - public void updateNeighborsAt(BlockPos pos, Block block) { + public void updateNeighborsAt(final BlockPos pos, final Block sourceBlock) { + // CraftBukkit start + if (this.populating) { + return; + } + // CraftBukkit end + if (captureBlockStates) { return; } // Paper - Cancel all physics during placement - this.updateNeighborsAt(pos, block, ExperimentalRedstoneUtils.initialOrientation(this, null, null)); + this.updateNeighborsAt(pos, sourceBlock, ExperimentalRedstoneUtils.initialOrientation(this, null, null)); } @Override - public void updateNeighborsAt(BlockPos pos, Block block, @Nullable Orientation orientation) { + public void updateNeighborsAt(final BlockPos pos, final Block sourceBlock, final @Nullable Orientation orientation) { + if (captureBlockStates) { return; } // Paper - Cancel all physics during placement - this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, null, orientation); + this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, null, orientation); } -@@ -1198,6 +_,44 @@ - WeightedList blockParticles, - Holder explosionSound +@@ -1214,6 +_,44 @@ + final WeightedList blockParticles, + final Holder explosionSound ) { + // CraftBukkit start -+ this.explode0(source, damageSource, damageCalculator, x, y, z, radius, fire, explosionInteraction, smallExplosionParticles, largeExplosionParticles, blockParticles, explosionSound); ++ this.explode0(source, damageSource, damageCalculator, x, y, z, r, fire, interactionType, smallExplosionParticles, largeExplosionParticles, blockParticles, explosionSound); + } + + public ServerExplosion explode0( -+ @Nullable Entity source, -+ @Nullable DamageSource damageSource, -+ @Nullable ExplosionDamageCalculator damageCalculator, -+ double x, -+ double y, -+ double z, -+ float radius, -+ boolean fire, -+ Level.ExplosionInteraction explosionInteraction, -+ ParticleOptions smallExplosionParticles, -+ ParticleOptions largeExplosionParticles, -+ WeightedList blockParticles, -+ Holder explosionSound ++ final @Nullable Entity source, ++ final @Nullable DamageSource damageSource, ++ final @Nullable ExplosionDamageCalculator damageCalculator, ++ final double x, ++ final double y, ++ final double z, ++ final float r, ++ final boolean fire, ++ final Level.ExplosionInteraction interactionType, ++ final ParticleOptions smallExplosionParticles, ++ final ParticleOptions largeExplosionParticles, ++ final WeightedList blockParticles, ++ final Holder explosionSound + ) { -+ return this.explode0(source, damageSource, damageCalculator, x, y, z, radius, fire, explosionInteraction, smallExplosionParticles, largeExplosionParticles, blockParticles, explosionSound, null); ++ return this.explode0(source, damageSource, damageCalculator, x, y, z, r, fire, interactionType, smallExplosionParticles, largeExplosionParticles, blockParticles, explosionSound, null); + } + public ServerExplosion explode0( -+ @Nullable Entity source, -+ @Nullable DamageSource damageSource, -+ @Nullable ExplosionDamageCalculator damageCalculator, -+ double x, -+ double y, -+ double z, -+ float radius, -+ boolean fire, -+ Level.ExplosionInteraction explosionInteraction, -+ ParticleOptions smallExplosionParticles, -+ ParticleOptions largeExplosionParticles, -+ WeightedList blockParticles, -+ Holder explosionSound, ++ final @Nullable Entity source, ++ final @Nullable DamageSource damageSource, ++ final @Nullable ExplosionDamageCalculator damageCalculator, ++ final double x, ++ final double y, ++ final double z, ++ final float r, ++ final boolean fire, ++ final Level.ExplosionInteraction interactionType, ++ final ParticleOptions smallExplosionParticles, ++ final ParticleOptions largeExplosionParticles, ++ final WeightedList blockParticles, ++ final Holder explosionSound, + java.util.function.@Nullable Consumer configurator + ) { + // CraftBukkit end - Explosion.BlockInteraction blockInteraction = switch (explosionInteraction) { + Explosion.BlockInteraction blockInteraction = switch (interactionType) { case NONE -> Explosion.BlockInteraction.KEEP; case BLOCK -> this.getDestroyType(GameRules.BLOCK_EXPLOSION_DROP_DECAY); -@@ -1206,10 +_,17 @@ +@@ -1222,10 +_,17 @@ : Explosion.BlockInteraction.KEEP; case TNT -> this.getDestroyType(GameRules.TNT_EXPLOSION_DROP_DECAY); case TRIGGER -> Explosion.BlockInteraction.TRIGGER_BLOCK; + case STANDARD -> Explosion.BlockInteraction.DESTROY; // CraftBukkit - handle custom explosion type }; - Vec3 vec3 = new Vec3(x, y, z); - ServerExplosion serverExplosion = new ServerExplosion(this, source, damageSource, damageCalculator, vec3, radius, fire, blockInteraction); -+ if (configurator != null) configurator.accept(serverExplosion);// Paper - Allow explosions to damage source - int i = serverExplosion.explode(); + Vec3 center = new Vec3(x, y, z); + ServerExplosion explosion = new ServerExplosion(this, source, damageSource, damageCalculator, center, r, fire, blockInteraction); ++ if (configurator != null) configurator.accept(explosion); // Paper - Allow explosions to damage source + int blockCount = explosion.explode(); + // CraftBukkit start -+ if (serverExplosion.wasCanceled) { -+ return serverExplosion; ++ if (explosion.wasCanceled) { ++ return explosion; + } + // CraftBukkit end - ParticleOptions particleOptions = serverExplosion.isSmall() ? smallExplosionParticles : largeExplosionParticles; + ParticleOptions explosionParticle = explosion.isSmall() ? smallExplosionParticles : largeExplosionParticles; - for (ServerPlayer serverPlayer : this.players) { -@@ -1218,6 +_,8 @@ - serverPlayer.connection.send(new ClientboundExplodePacket(vec3, radius, i, optional, particleOptions, explosionSound, blockParticles)); + for (ServerPlayer player : this.players) { +@@ -1234,6 +_,8 @@ + player.connection.send(new ClientboundExplodePacket(center, r, blockCount, playerKnockback, explosionParticle, explosionSound, blockParticles)); } } + -+ return serverExplosion; // CraftBukkit ++ return explosion; // CraftBukkit } - private Explosion.BlockInteraction getDestroyType(GameRule decayGameRule) { -@@ -1287,19 +_,55 @@ - public int sendParticles( - T options, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed + private Explosion.BlockInteraction getDestroyType(final GameRule gameRule) { +@@ -1311,7 +_,7 @@ + final double zDist, + final double speed ) { -- return this.sendParticles(options, false, false, x, y, z, count, xDist, yDist, zDist, speed); -+ return this.sendParticlesSource(null, options, false, false, x, y, z, count, xDist, yDist, zDist, speed); // CraftBukkit - visibility api support +- return this.sendParticles(particle, false, false, x, y, z, count, xDist, yDist, zDist, speed); ++ return this.sendParticlesSource(null, particle, false, false, x, y, z, count, xDist, yDist, zDist, speed); // CraftBukkit - visibility api support } public int sendParticles( - T options, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed +@@ -1327,13 +_,49 @@ + final double zDist, + final double speed ) { + // Paper start - visibility api support -+ return this.sendParticlesSource(null, options, overrideLimiter, alwaysShow, x, y, z, count, xDist, yDist, zDist, speed); ++ return this.sendParticlesSource(null, particle, overrideLimiter, alwaysShow, x, y, z, count, xDist, yDist, zDist, speed); + } + public int sendParticlesSource( + @Nullable Entity sender, @@ -898,7 +927,7 @@ + public int sendParticlesSource( + List receivers, + @Nullable Entity sender, -+ T options, ++ T particle, + boolean overrideLimiter, + boolean alwaysShow, + double x, @@ -911,41 +940,41 @@ + double speed + ) { + // Paper end - visibility api support - ClientboundLevelParticlesPacket clientboundLevelParticlesPacket = new ClientboundLevelParticlesPacket( - options, overrideLimiter, alwaysShow, x, y, z, (float)xDist, (float)yDist, (float)zDist, (float)speed, count + ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket( + particle, overrideLimiter, alwaysShow, x, y, z, (float)xDist, (float)yDist, (float)zDist, (float)speed, count ); - int i = 0; - -- for (int i1 = 0; i1 < this.players.size(); i1++) { -- ServerPlayer serverPlayer = this.players.get(i1); -+ for (int i1 = 0; i1 < receivers.size(); i1++) { // Paper - particle API -+ ServerPlayer serverPlayer = receivers.get(i1); // Paper - particle API -+ if (sender != null && !serverPlayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit - if (this.sendParticles(serverPlayer, overrideLimiter, x, y, z, clientboundLevelParticlesPacket)) { - i++; + int result = 0; + +- for (int i = 0; i < this.players.size(); i++) { +- ServerPlayer player = this.players.get(i); ++ for (int i = 0; i < receivers.size(); i++) { // Paper - particle API ++ ServerPlayer player = receivers.get(i); // Paper - particle API ++ if (sender != null && !player.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit + if (this.sendParticles(player, overrideLimiter, x, y, z, packet)) { + result++; } -@@ -1383,7 +_,7 @@ - } - - public @Nullable BlockPos findNearestMapStructure(TagKey structureTag, BlockPos pos, int radius, boolean skipKnownStructures) { -- if (!this.server.getWorldData().worldGenOptions().generateStructures()) { -+ if (!this.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit +@@ -1421,7 +_,7 @@ + public @Nullable BlockPos findNearestMapStructure( + final TagKey structureTag, final BlockPos origin, final int maxSearchRadius, final boolean createReference + ) { +- if (!this.server.getWorldGenSettings().options().generateStructures()) { ++ if (!this.worldDataAndGenSettings.genSettings().options().generateStructures()) { // CraftBukkit return null; } else { - Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); -@@ -1435,10 +_,36 @@ + Optional> tag = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); +@@ -1479,10 +_,36 @@ @Override - public @Nullable MapItemSavedData getMapData(MapId mapId) { -- return this.getServer().overworld().getDataStorage().get(MapItemSavedData.type(mapId)); + public @Nullable MapItemSavedData getMapData(final MapId id) { +- return this.getServer().getDataStorage().get(MapItemSavedData.type(id)); + // Paper start - Call missing map initialize event and set id -+ final DimensionDataStorage storage = this.getServer().overworld().getDataStorage(); ++ final SavedDataStorage storage = this.getServer().getDataStorage(); + -+ final Optional cacheEntry = storage.cache.get(MapItemSavedData.type(mapId)); ++ final Optional cacheEntry = storage.cache.get(MapItemSavedData.type(id)); + if (cacheEntry == null) { // Cache did not contain, try to load and may init -+ final MapItemSavedData mapData = storage.get(MapItemSavedData.type(mapId)); // get populates the cache ++ final MapItemSavedData mapData = storage.get(MapItemSavedData.type(id)); // get populates the cache + if (mapData != null) { // map was read, init it and return -+ mapData.id = mapId; ++ mapData.id = id; + new org.bukkit.event.server.MapInitializeEvent(mapData.mapView).callEvent(); + return mapData; + } @@ -954,7 +983,7 @@ + } + // Cache entry exists, update it with the id ref and return. + if (cacheEntry.orElse(null) instanceof final MapItemSavedData mapItemSavedData) { -+ mapItemSavedData.id = mapId; ++ mapItemSavedData.id = id; + return mapItemSavedData; + } + @@ -962,19 +991,19 @@ + // Paper end - Call missing map initialize event and set id } - public void setMapData(MapId mapId, MapItemSavedData data) { + public void setMapData(final MapId id, final MapItemSavedData data) { + // CraftBukkit start -+ data.id = mapId; ++ data.id = id; + org.bukkit.event.server.MapInitializeEvent event = new org.bukkit.event.server.MapInitializeEvent(data.mapView); + event.callEvent(); + // CraftBukkit end - this.getServer().overworld().getDataStorage().set(MapItemSavedData.type(mapId), data); + this.getServer().getDataStorage().set(MapItemSavedData.type(id), data); } -@@ -1448,7 +_,19 @@ +@@ -1492,7 +_,19 @@ @Override - public void setRespawnData(LevelData.RespawnData respawnData) { + public void setRespawnData(final LevelData.RespawnData respawnData) { - this.getServer().setRespawnData(respawnData); + // Paper start + if (!this.serverLevelData.getRespawnData().positionEquals(respawnData)) { @@ -992,19 +1021,19 @@ } @Override -@@ -1485,6 +_,11 @@ - this.debugSynchronizers.dropPoi(blockPos); +@@ -1529,6 +_,11 @@ + this.debugSynchronizers.dropPoi(immutable); })); - optional1.ifPresent(holder -> this.getServer().execute(() -> { + newType.ifPresent(poiType -> this.getServer().execute(() -> { + // Paper start - Remove stale POIs -+ if (optional.isEmpty() && this.getPoiManager().exists(blockPos, ignored -> true)) { -+ this.getPoiManager().remove(blockPos); ++ if (oldType.isEmpty() && this.getPoiManager().exists(pos, _ -> true)) { ++ this.getPoiManager().remove(pos); + } + // Paper end - Remove stale POIs - PoiRecord poiRecord = this.getPoiManager().add(blockPos, (Holder)holder); - if (poiRecord != null) { - this.debugSynchronizers.registerPoi(poiRecord); -@@ -1638,12 +_,12 @@ + PoiRecord record = this.getPoiManager().add(immutable, (Holder)poiType); + if (record != null) { + this.debugSynchronizers.registerPoi(record); +@@ -1677,12 +_,12 @@ } public boolean isFlat() { @@ -1014,12 +1043,21 @@ @Override public long getSeed() { -- return this.server.getWorldData().worldGenOptions().seed(); -+ return this.serverLevelData.worldGenOptions().seed(); // CraftBukkit +- return this.server.getWorldGenSettings().options().seed(); ++ return this.worldDataAndGenSettings.genSettings().options().seed(); // CraftBukkit + } + + public @Nullable EnderDragonFight getDragonFight() { +@@ -1690,7 +_,7 @@ } - public @Nullable EndDragonFight getDragonFight() { -@@ -1693,6 +_,7 @@ + public WeatherData getWeatherData() { +- return this.server.getWeatherData(); ++ return this.weatherData; // Paper - per-level WeatherData + } + + @Override +@@ -1737,6 +_,7 @@ @Override public LevelEntityGetter getEntities() { @@ -1027,10 +1065,23 @@ return this.entityManager.getEntityGetter(); } -@@ -1808,6 +_,28 @@ - return this.serverLevelData.getGameRules(); +@@ -1785,6 +_,7 @@ + public void close() throws IOException { + super.close(); + this.entityManager.close(); ++ this.savedDataStorage.close(); // Paper - save per-world data in level storage + } + + @Override +@@ -1841,8 +_,30 @@ } + public GameRules getGameRules() { +- return this.server.getGameRules(); +- } ++ return this.gameRules; // Paper - per-level GameRules ++ } ++ + // Paper start - respect global sound events gamerule + public List getPlayersForGlobalSoundGamerule() { + return this.getGameRules().get(GameRules.GLOBAL_SOUND_EVENTS) ? ((ServerLevel) this).getServer().getPlayerList().players : ((ServerLevel) this).players(); @@ -1052,28 +1103,27 @@ + } + } + // Paper end - notify observers even if grow failed -+ + @Override - public CrashReportCategory fillReportDetails(CrashReport report) { - CrashReportCategory crashReportCategory = super.fillReportDetails(report); -@@ -1852,6 +_,7 @@ - if (entity instanceof WaypointTransmitter waypointTransmitter && waypointTransmitter.isTransmittingWaypoint()) { - ServerLevel.this.getWaypointManager().trackWaypoint(waypointTransmitter); + public CrashReportCategory fillReportDetails(final CrashReport report) { +@@ -1905,6 +_,7 @@ + if (entity instanceof WaypointTransmitter waypoint && waypoint.isTransmittingWaypoint()) { + ServerLevel.this.getWaypointManager().trackWaypoint(waypoint); } + entity.setOldPosAndRot(); // Paper - update old pos / rot for new entities as it will default to Vec3.ZERO } @Override -@@ -1865,17 +_,24 @@ +@@ -1918,17 +_,24 @@ @Override - public void onTickingStart(Entity entity) { + public void onTickingStart(final Entity entity) { + if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking ServerLevel.this.entityTickList.add(entity); } @Override - public void onTickingEnd(Entity entity) { + public void onTickingEnd(final Entity entity) { ServerLevel.this.entityTickList.remove(entity); + // Paper start - Reset pearls when they stop being ticked + if (ServerLevel.this.paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && ServerLevel.this.paperConfig().misc.legacyEnderPearlBehavior && entity instanceof net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownEnderpearl pearl) { @@ -1083,23 +1133,23 @@ } @Override - public void onTrackingStart(Entity entity) { + public void onTrackingStart(final Entity entity) { - ServerLevel.this.getChunkSource().addEntity(entity); + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot + // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true - if (entity instanceof ServerPlayer serverPlayer) { - ServerLevel.this.players.add(serverPlayer); - if (serverPlayer.isReceivingWaypoints()) { -@@ -1890,7 +_,7 @@ + if (entity instanceof ServerPlayer player) { + ServerLevel.this.players.add(player); + if (player.isReceivingWaypoints()) { +@@ -1943,7 +_,7 @@ } if (entity instanceof Mob mob) { - if (ServerLevel.this.isUpdatingNavigations) { + if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning - String string = "onTrackingStart called during navigation iteration"; + String message = "onTrackingStart called during navigation iteration"; Util.logAndPauseIfInIde( "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") -@@ -1907,10 +_,52 @@ +@@ -1960,10 +_,52 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -1119,7 +1169,7 @@ } @Override - public void onTrackingEnd(Entity entity) { + public void onTrackingEnd(final Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot + // Spigot start // TODO I don't think this is needed anymore + if (entity instanceof Player player) { @@ -1150,18 +1200,18 @@ + } + // Spigot end ServerLevel.this.getChunkSource().removeEntity(entity); - if (entity instanceof ServerPlayer serverPlayer) { - ServerLevel.this.players.remove(serverPlayer); -@@ -1919,7 +_,7 @@ + if (entity instanceof ServerPlayer player) { + ServerLevel.this.players.remove(player); +@@ -1972,7 +_,7 @@ } if (entity instanceof Mob mob) { - if (ServerLevel.this.isUpdatingNavigations) { + if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning - String string = "onTrackingStart called during navigation iteration"; + String message = "onTrackingStart called during navigation iteration"; Util.logAndPauseIfInIde( "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") -@@ -1937,6 +_,15 @@ +@@ -1990,6 +_,15 @@ entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); ServerLevel.this.debugSynchronizers.dropEntity(entity); @@ -1177,7 +1227,7 @@ } @Override -@@ -1944,4 +_,24 @@ +@@ -1997,4 +_,24 @@ entity.updateDynamicGameEventListener(DynamicGameEventListener::move); } } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index 9fdbd77f61e2..6906c9782aa7 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -251,7 +_,8 @@ +@@ -253,7 +_,8 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance = 2; @@ -10,7 +10,7 @@ private @Nullable Vec3 startingToFallPosition; private @Nullable Vec3 enteredNetherPosition; private @Nullable Vec3 enteredLavaOnVehiclePosition; -@@ -295,6 +_,13 @@ +@@ -308,6 +_,13 @@ } } @@ -22,9 +22,9 @@ + // Paper end - Sync offhand slot in menus + @Override - public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack stack) { - ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slot, stack)); -@@ -330,6 +_,32 @@ + public void sendSlotChange(final AbstractContainerMenu container, final int slotIndex, final ItemStack itemStack) { + ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slotIndex, itemStack)); +@@ -347,6 +_,32 @@ } } @@ -55,10 +55,10 @@ + // Paper end - Add PlayerInventorySlotChangeEvent + @Override - public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { + public void dataChanged(final AbstractContainerMenu container, final int id, final int value) { } -@@ -356,10 +_,43 @@ - public void sendSystemMessage(Component message) { +@@ -377,10 +_,43 @@ + public void sendSystemMessage(final Component message) { ServerPlayer.this.sendSystemMessage(message); } + @@ -99,10 +99,10 @@ + public com.destroystokyo.paper.event.entity.@Nullable PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent + public org.bukkit.event.player.PlayerQuitEvent.@Nullable QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event - public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) { + public ServerPlayer(final MinecraftServer server, final ServerLevel level, final GameProfile gameProfile, final ClientInformation clientInformation) { super(level, gameProfile); -@@ -370,8 +_,14 @@ - this.recipeBook = new ServerRecipeBook((recipe, output) -> server.getRecipeManager().listDisplaysForRecipe(recipe, output)); +@@ -391,8 +_,14 @@ + this.recipeBook = new ServerRecipeBook((id, output) -> server.getRecipeManager().listDisplaysForRecipe(id, output)); this.stats = server.getPlayerList().getPlayerStats(this); this.advancements = server.getPlayerList().getPlayerAdvancements(this); - this.updateOptions(clientInformation); @@ -117,15 +117,15 @@ } @Override -@@ -389,6 +_,7 @@ +@@ -410,6 +_,7 @@ this.seenCredits = input.getBooleanOr("seenCredits", false); input.read("recipeBook", ServerRecipeBook.Packed.CODEC) - .ifPresent(packed -> this.recipeBook.loadUntrusted(packed, key -> this.server.getRecipeManager().byKey(key).isPresent())); + .ifPresent(p -> this.recipeBook.loadUntrusted(p, id -> this.server.getRecipeManager().byKey(id).isPresent())); + this.getBukkitEntity().readExtraData(input); // CraftBukkit if (this.isSleeping()) { this.stopSleeping(); } -@@ -396,6 +_,19 @@ +@@ -417,6 +_,19 @@ this.respawnConfig = input.read("respawn", ServerPlayer.RespawnConfig.CODEC).orElse(null); this.spawnExtraParticlesOnFall = input.getBooleanOr("spawn_extra_particles_on_fall", false); this.raidOmenPosition = input.read("raid_omen_position", BlockPos.CODEC).orElse(null); @@ -145,14 +145,14 @@ this.gameMode .setGameModeForPlayer(this.calculateGameModeForNewPlayer(readPlayerMode(input, "playerGameType")), readPlayerMode(input, "previousPlayerGameType")); this.setShoulderEntityLeft(input.read("ShoulderEntityLeft", CompoundTag.CODEC).orElseGet(CompoundTag::new)); -@@ -423,12 +_,24 @@ +@@ -444,12 +_,24 @@ if (!this.getShoulderEntityRight().isEmpty()) { output.store("ShoulderEntityRight", CompoundTag.CODEC, this.getShoulderEntityRight()); } + this.getBukkitEntity().setExtraData(output); // CraftBukkit } - private void saveParentVehicle(ValueOutput output) { + private void saveParentVehicle(final ValueOutput playerOutput) { Entity rootVehicle = this.getRootVehicle(); Entity vehicle = this.getVehicle(); - if (vehicle != null && rootVehicle != this && rootVehicle.hasExactlyOnePlayerPassenger()) { @@ -168,40 +168,40 @@ + } + if (persistVehicle && vehicle != null && rootVehicle != this && rootVehicle.hasExactlyOnePlayerPassenger() && !rootVehicle.isRemoved()) { // Paper - Ensure valid vehicle status + // CraftBukkit end - ValueOutput valueOutput = output.child("RootVehicle"); - valueOutput.store("Attach", UUIDUtil.CODEC, vehicle.getUUID()); - rootVehicle.save(valueOutput.child("Entity")); -@@ -440,7 +_,7 @@ - if (!optional.isEmpty()) { + ValueOutput vehicleWrapper = playerOutput.child("RootVehicle"); + vehicleWrapper.store("Attach", UUIDUtil.CODEC, vehicle.getUUID()); + rootVehicle.save(vehicleWrapper.child("Entity")); +@@ -461,7 +_,7 @@ + if (!rootTag.isEmpty()) { ServerLevel serverLevel = this.level(); - Entity entity = EntityType.loadEntityRecursive( -- optional.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2) ? null : entity2 -+ optional.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2 // Paper - Entity#getEntitySpawnReason + Entity vehicle = EntityType.loadEntityRecursive( +- rootTag.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, e -> !serverLevel.addWithUUID(e) ? null : e ++ rootTag.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, e -> !serverLevel.addWithUUID(e, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : e // Paper - Entity#getEntitySpawnReason ); - if (entity != null) { - UUID uuid = optional.get().read("Attach", UUIDUtil.CODEC).orElse(null); -@@ -457,10 +_,10 @@ + if (vehicle != null) { + UUID attachTo = rootTag.get().read("Attach", UUIDUtil.CODEC).orElse(null); +@@ -478,10 +_,10 @@ if (!this.isPassenger()) { LOGGER.warn("Couldn't reattach entity to player"); -- entity.discard(); -+ entity.discard(null); // CraftBukkit - add Bukkit remove cause +- vehicle.discard(); ++ vehicle.discard(null); // CraftBukkit - add Bukkit remove cause - for (Entity entity1x : entity.getIndirectPassengers()) { -- entity1x.discard(); -+ entity1x.discard(null); // CraftBukkit - add Bukkit remove cause + for (Entity entityx : vehicle.getIndirectPassengers()) { +- entityx.discard(); ++ entityx.discard(null); // CraftBukkit - add Bukkit remove cause } } } -@@ -472,6 +_,7 @@ - ValueOutput.ValueOutputList valueOutputList = output.childrenList("ender_pearls"); +@@ -493,6 +_,7 @@ + ValueOutput.ValueOutputList pearlsOutput = playerOutput.childrenList("ender_pearls"); - for (ThrownEnderpearl thrownEnderpearl : this.enderPearls) { -+ if (thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior - if (thrownEnderpearl.isRemoved()) { + for (ThrownEnderpearl enderPearl : this.enderPearls) { ++ if (enderPearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior + if (enderPearl.isRemoved()) { LOGGER.warn("Trying to save removed ender pearl, skipping"); } else { -@@ -504,6 +_,16 @@ +@@ -527,6 +_,16 @@ } } @@ -215,10 +215,10 @@ + } + // CraftBukkit end + - public void setExperiencePoints(int experiencePoints) { - float f = this.getXpNeededForNextLevel(); - float f1 = (f - 1.0F) / f; -@@ -568,6 +_,11 @@ + public void setExperiencePoints(final int amount) { + float limit = this.getXpNeededForNextLevel(); + float max = (limit - 1.0F) / limit; +@@ -591,6 +_,11 @@ @Override public void tick() { @@ -230,7 +230,7 @@ this.connection.tickClientLoadTimeout(); this.gameMode.tick(); this.wardenSpawnTracker.tick(); -@@ -575,9 +_,18 @@ +@@ -598,9 +_,18 @@ this.invulnerableTime--; } @@ -252,7 +252,7 @@ this.containerMenu = this.inventoryMenu; } -@@ -636,10 +_,10 @@ +@@ -659,10 +_,10 @@ public void doTick() { try { @@ -265,7 +265,7 @@ this.containerMenu = this.inventoryMenu; } -@@ -669,7 +_,7 @@ +@@ -692,7 +_,7 @@ if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { @@ -274,7 +274,7 @@ this.lastSentHealth = this.getHealth(); this.lastSentFood = this.foodData.getFoodLevel(); this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; -@@ -700,6 +_,12 @@ +@@ -723,6 +_,12 @@ this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float)this.lastRecordedExperience)); } @@ -287,7 +287,7 @@ if (this.experienceLevel != this.lastRecordedLevel) { this.lastRecordedLevel = this.experienceLevel; this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float)this.lastRecordedLevel)); -@@ -713,6 +_,21 @@ +@@ -736,6 +_,21 @@ if (this.tickCount % 20 == 0) { CriteriaTriggers.LOCATION.trigger(this); } @@ -307,9 +307,9 @@ + } + // CraftBukkit end } catch (Throwable var4) { - CrashReport crashReport = CrashReport.forThrowable(var4, "Ticking player"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Player being ticked"); -@@ -737,7 +_,7 @@ + CrashReport report = CrashReport.forThrowable(var4, "Ticking player"); + CrashReportCategory category = report.addCategory("Player being ticked"); +@@ -760,7 +_,7 @@ if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.level().getGameRules().get(GameRules.NATURAL_HEALTH_REGENERATION)) { if (this.tickCount % 20 == 0) { if (this.getHealth() < this.getMaxHealth()) { @@ -317,8 +317,8 @@ + this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit - added regain reason of "REGEN" for filtering purposes. } - float saturationLevel = this.foodData.getSaturationLevel(); -@@ -757,6 +_,7 @@ + float saturation = this.foodData.getSaturationLevel(); +@@ -780,6 +_,7 @@ this.playShoulderEntityAmbientSound(this.getShoulderEntityLeft()); this.playShoulderEntityAmbientSound(this.getShoulderEntityRight()); if (this.fallDistance > 0.5 || this.isInWater() || this.getAbilities().flying || this.isSleeping() || this.isInPowderSnow) { @@ -326,7 +326,7 @@ this.removeEntitiesOnShoulder(); } } -@@ -801,35 +_,64 @@ +@@ -824,33 +_,62 @@ @Override public void removeEntitiesOnShoulder() { if (this.timeEntitySatOnShoulder + 20L < this.level().getGameTime()) { @@ -361,29 +361,27 @@ } + // Paper end - release entity api -- private void respawnEntityOnShoulder(CompoundTag tag) { -+ private boolean respawnEntityOnShoulder(CompoundTag tag) { // CraftBukkit - void -> boolean +- private void respawnEntityOnShoulder(final CompoundTag tag) { ++ private boolean respawnEntityOnShoulder(final CompoundTag tag) { // CraftBukkit - void -> boolean + // Paper start - release entity api - return entity - overload + return this.respawnEntityOnShoulder0(tag) != null; + } + @Nullable -+ private Entity respawnEntityOnShoulder0(CompoundTag tag) { // CraftBukkit void->boolean ++ private Entity respawnEntityOnShoulder0(final CompoundTag tag) { // CraftBukkit void->boolean + // Paper end - release entity api - return entity - overload - ServerLevel scopedCollector = this.level(); - if (scopedCollector instanceof ServerLevel) { - ServerLevel serverLevel = scopedCollector; + ServerLevel reporter = this.level(); + if (reporter instanceof ServerLevel) { + ServerLevel serverLevel = reporter; if (!tag.isEmpty()) { - try (ProblemReporter.ScopedCollector scopedCollectorx = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { + try (ProblemReporter.ScopedCollector reporterx = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { - EntityType.create( + return EntityType.create( // Paper - release entity api - TagValueInput.create(scopedCollectorx.forChild(() -> ".shoulder"), serverLevel.registryAccess(), tag), - serverLevel, - EntitySpawnReason.LOAD + TagValueInput.create(reporterx.forChild(() -> ".shoulder"), serverLevel.registryAccess(), tag), serverLevel, EntitySpawnReason.LOAD ) - .ifPresent(entity -> { + .map(entity -> { // Paper - release entity api - if (entity instanceof TamableAnimal tamableAnimal) { - tamableAnimal.setOwner(this); + if (entity instanceof TamableAnimal tamed) { + tamed.setOwner(this); } entity.setPos(this.getX(), this.getY() + 0.7F, this.getZ()); @@ -398,20 +396,20 @@ } @Override -@@ -866,15 +_,36 @@ +@@ -887,15 +_,36 @@ } - private void updateScoreForCriteria(ObjectiveCriteria criteria, int points) { -- this.level().getScoreboard().forAllObjectives(criteria, this, score -> score.set(points)); + private void updateScoreForCriteria(final ObjectiveCriteria criteria, final int value) { +- this.level().getScoreboard().forAllObjectives(criteria, this, score -> score.set(value)); - } - - @Override -- public void die(DamageSource damageSource) { +- public void die(final DamageSource source) { - this.gameEvent(GameEvent.ENTITY_DIE); -- boolean flag = this.level().getGameRules().get(GameRules.SHOW_DEATH_MESSAGES); -- if (flag) { +- boolean showDeathMessage = this.level().getGameRules().get(GameRules.SHOW_DEATH_MESSAGES); +- if (showDeathMessage) { - Component deathMessage = this.getCombatTracker().getDeathMessage(); -+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria, this, scoreAccess -> scoreAccess.set(points)); // CraftBukkit - Use our scores instead ++ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria, this, score -> score.set(value)); // CraftBukkit - Use our scores instead + } + + // Paper start - PlayerDeathEvent#getItemsToKeep @@ -444,7 +442,7 @@ this.connection .send( new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage), -@@ -891,6 +_,65 @@ +@@ -912,6 +_,64 @@ } ) ); @@ -454,9 +452,9 @@ + } + // Paper end - Expand PlayerDeathEvent API + @Override -+ public void die(DamageSource damageSource) { ++ public void die(final DamageSource source) { + // this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check -+ boolean flag = this.level().getGameRules().get(GameRules.SHOW_DEATH_MESSAGES); final boolean showDeathMessage = flag; // Paper - OBFHELPER ++ boolean showDeathMessage = this.level().getGameRules().get(GameRules.SHOW_DEATH_MESSAGES); + // CraftBukkit start - fire PlayerDeathEvent + if (this.isRemoved()) { + return; @@ -472,7 +470,7 @@ + } + if (!this.isSpectator() && this.shouldDropLoot(this.level())) { // Paper - fix player loottables running when mob loot gamerule is false + // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) -+ this.dropFromLootTable(this.level(), damageSource, this.lastHurtByPlayerMemoryTime > 0); ++ this.dropFromLootTable(this.level(), source, this.lastHurtByPlayerMemoryTime > 0); + // Paper - Restore vanilla drops behaviour; custom death loot is a noop on server player, remove. + loot.addAll(this.drops); + this.drops.clear(); // SPIGOT-5188: make sure to clear @@ -480,9 +478,8 @@ + + Component defaultMessage = this.getCombatTracker().getDeathMessage(); + -+ String deathmessage = defaultMessage.getString(); + this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel -+ org.bukkit.event.entity.PlayerDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerDeathEvent(this, damageSource, loot, io.papermc.paper.adventure.PaperAdventure.asAdventure(defaultMessage), showDeathMessage, keepInventory); // Paper - Adventure; Expand PlayerDeathEvent API ++ org.bukkit.event.entity.PlayerDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerDeathEvent(this, source, loot, io.papermc.paper.adventure.PaperAdventure.asAdventure(defaultMessage), showDeathMessage, keepInventory); // Paper - Adventure; Expand PlayerDeathEvent API + // Paper start - cancellable death event + if (event.isCancelled()) { + // make compatible with plugins that might have already set the health in an event listener @@ -510,7 +507,7 @@ Team team = this.getTeam(); if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) { this.server.getPlayerList().broadcastSystemMessage(deathMessage, false); -@@ -900,7 +_,7 @@ +@@ -921,7 +_,7 @@ this.server.getPlayerList().broadcastSystemToAllExceptTeam(this, deathMessage); } } else { @@ -519,14 +516,14 @@ } this.removeEntitiesOnShoulder(); -@@ -908,11 +_,35 @@ +@@ -929,11 +_,35 @@ this.tellNeutralMobsThatIDied(); } - if (!this.isSpectator()) { -- this.dropAllDeathLoot(this.level(), damageSource); +- this.dropAllDeathLoot(this.level(), source); + // SPIGOT-5478 must be called manually now -+ if (event.shouldDropExperience()) this.dropExperience(this.level(), damageSource.getEntity()); // Paper - tie to event ++ if (event.shouldDropExperience()) this.dropExperience(this.level(), source.getEntity()); // Paper - tie to event + // we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory. + if (!event.getKeepInventory()) { + // Paper start - PlayerDeathEvent#getItemsToKeep @@ -555,50 +552,50 @@ + // CraftBukkit end + + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead - LivingEntity killCredit = this.getKillCredit(); - if (killCredit != null) { - this.awardStat(Stats.ENTITY_KILLED_BY.get(killCredit.getType())); -@@ -946,10 +_,10 @@ - if (entity != this) { - super.awardKillScore(entity, damageSource); + LivingEntity killer = this.getKillCredit(); + if (killer != null) { + this.awardStat(Stats.ENTITY_KILLED_BY.get(killer.getType())); +@@ -967,10 +_,10 @@ + if (victim != this) { + super.awardKillScore(victim, killingBlow); Scoreboard scoreboard = this.level().getScoreboard(); - scoreboard.forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment); + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead - if (entity instanceof Player) { + if (victim instanceof Player) { this.awardStat(Stats.PLAYER_KILLS); - scoreboard.forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment); + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead } else { this.awardStat(Stats.MOB_KILLS); } -@@ -961,12 +_,11 @@ - } - - private void handleTeamKill(ScoreHolder scoreHolder, ScoreHolder teamMember, ObjectiveCriteria[] criteria) { -- Scoreboard scoreboard = this.level().getScoreboard(); -- PlayerTeam playersTeam = scoreboard.getPlayersTeam(teamMember.getScoreboardName()); -+ PlayerTeam playersTeam = this.getBukkitEntity().getScoreboard().getHandle().getPlayersTeam(teamMember.getScoreboardName()); // CraftBukkit - if (playersTeam != null) { - int id = playersTeam.getColor().getId(); - if (id >= 0 && id < criteria.length) { -- scoreboard.forAllObjectives(criteria[id], scoreHolder, ScoreAccess::increment); -+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria[id], scoreHolder, ScoreAccess::increment); // CraftBukkit - Get our scores instead +@@ -983,11 +_,11 @@ + + private void handleTeamKill(final ScoreHolder source, final ScoreHolder target, final ObjectiveCriteria[] criteriaByTeam) { + Scoreboard scoreboard = this.level().getScoreboard(); +- PlayerTeam ownTeam = scoreboard.getPlayersTeam(target.getScoreboardName()); ++ PlayerTeam ownTeam = this.getBukkitEntity().getScoreboard().getHandle().getPlayersTeam(target.getScoreboardName()); // CraftBukkit + if (ownTeam != null) { + int color = ownTeam.getColor().getId(); + if (color >= 0 && color < criteriaByTeam.length) { +- scoreboard.forAllObjectives(criteriaByTeam[color], source, ScoreAccess::increment); ++ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteriaByTeam[color], source, ScoreAccess::increment); // CraftBukkit - Get our scores instead } } } -@@ -977,9 +_,20 @@ +@@ -998,9 +_,20 @@ return false; } else { - Entity entity = damageSource.getEntity(); -- return !(entity instanceof Player player && !this.canHarmPlayer(player)) + Entity entity = source.getEntity(); +- return !(entity instanceof Player playerx && !this.canHarmPlayer(playerx)) +- && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player player && !this.canHarmPlayer(player)) +- && super.hurtServer(level, source, damage); + if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. -+ !(entity instanceof Player player && !this.canHarmPlayer(player)) - && !(entity instanceof AbstractArrow abstractArrow && abstractArrow.getOwner() instanceof Player player1 && !this.canHarmPlayer(player1)) -- && super.hurtServer(level, damageSource, amount); ++ !(entity instanceof Player playerx && !this.canHarmPlayer(playerx)) ++ && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player player && !this.canHarmPlayer(player)) + )) return false; // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. + // Paper start - cancellable death events + this.queueHealthUpdatePacket = true; -+ boolean damaged = super.hurtServer(level, damageSource, amount); ++ boolean damaged = super.hurtServer(level, source, damage); + this.queueHealthUpdatePacket = false; + if (this.queuedHealthUpdatePacket != null) { + this.connection.send(this.queuedHealthUpdatePacket); @@ -609,39 +606,47 @@ } } -@@ -992,22 +_,92 @@ +@@ -1013,24 +_,98 @@ return this.level().isPvpAllowed(); } -- public TeleportTransition findRespawnPositionAndUseSpawnBlock(boolean useCharge, TeleportTransition.PostTeleportTransition postTeleportTransition) { +- public TeleportTransition findRespawnPositionAndUseSpawnBlock( +- final boolean consumeSpawnBlock, final TeleportTransition.PostTeleportTransition postTeleportTransition +- ) { + // Paper start + public record RespawnResult(TeleportTransition transition, boolean isBedSpawn, boolean isAnchorSpawn) { + } + -+ public @Nullable TeleportTransition findRespawnPositionAndUseSpawnBlock(boolean useCharge, TeleportTransition.PostTeleportTransition postTeleportTransition, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason) { -+ RespawnResult result = this.findRespawnPositionAndUseSpawnBlock0(useCharge, postTeleportTransition, respawnReason); ++ public @Nullable TeleportTransition findRespawnPositionAndUseSpawnBlock( ++ final boolean consumeSpawnBlock, final TeleportTransition.PostTeleportTransition postTeleportTransition, ++ final org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason ++ ) { ++ RespawnResult result = this.findRespawnPositionAndUseSpawnBlock0(consumeSpawnBlock, postTeleportTransition, respawnReason); + return result == null ? null : result.transition(); + } + -+ public @Nullable RespawnResult findRespawnPositionAndUseSpawnBlock0(boolean useCharge, TeleportTransition.PostTeleportTransition postTeleportTransition, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason) { ++ public @Nullable RespawnResult findRespawnPositionAndUseSpawnBlock0( ++ final boolean consumeSpawnBlock, final TeleportTransition.PostTeleportTransition postTeleportTransition, ++ final org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason ++ ) { + TeleportTransition teleportTransition; + boolean isBedSpawn = false; + boolean isAnchorSpawn = false; + Runnable consumeAnchorCharge = null; + // Paper end ServerPlayer.RespawnConfig respawnConfig = this.getRespawnConfig(); - ServerLevel level = this.server.getLevel(ServerPlayer.RespawnConfig.getDimensionOrDefault(respawnConfig)); - if (level != null && respawnConfig != null) { - Optional optional = findRespawnAndUseSpawnBlock(level, respawnConfig, useCharge); - if (optional.isPresent()) { - ServerPlayer.RespawnPosAngle respawnPosAngle = optional.get(); + ServerLevel respawnLevel = this.server.getLevel(ServerPlayer.RespawnConfig.getDimensionOrDefault(respawnConfig)); + if (respawnLevel != null && respawnConfig != null) { + Optional respawn = findRespawnAndUseSpawnBlock(respawnLevel, respawnConfig, consumeSpawnBlock); + if (respawn.isPresent()) { + ServerPlayer.RespawnPosAngle respawnPosAngle = respawn.get(); - return new TeleportTransition( + // CraftBukkit start + isBedSpawn = respawnPosAngle.isBedSpawn(); + isAnchorSpawn = respawnPosAngle.isAnchorSpawn(); + consumeAnchorCharge = respawnPosAngle.consumeAnchorCharge(); + teleportTransition = new TeleportTransition( - level, respawnPosAngle.position(), Vec3.ZERO, respawnPosAngle.yaw(), respawnPosAngle.pitch(), postTeleportTransition + respawnLevel, respawnPosAngle.position(), Vec3.ZERO, respawnPosAngle.yaw(), respawnPosAngle.pitch(), postTeleportTransition ); + // CraftBukkit end } else { @@ -707,60 +712,62 @@ } public boolean isReceivingWaypoints() { -@@ -1042,14 +_,16 @@ - && (flag || blockState.getValue(RespawnAnchorBlock.CHARGE) > 0) - && RespawnAnchorBlock.canSetSpawn(level, blockPos)) { - Optional optional = RespawnAnchorBlock.findStandUpPosition(EntityType.PLAYER, level, blockPos); +@@ -1064,15 +_,17 @@ + if (block instanceof RespawnAnchorBlock && (forced || blockState.getValue(RespawnAnchorBlock.CHARGE) > 0) && RespawnAnchorBlock.canSetSpawn(level, pos) + ) + { + Runnable consumeAnchorCharge = null; // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) - if (!flag && useCharge && optional.isPresent()) { -- level.setBlock(blockPos, blockState.setValue(RespawnAnchorBlock.CHARGE, blockState.getValue(RespawnAnchorBlock.CHARGE) - 1), Block.UPDATE_ALL); -+ consumeAnchorCharge = () -> level.setBlock(blockPos, blockState.setValue(RespawnAnchorBlock.CHARGE, blockState.getValue(RespawnAnchorBlock.CHARGE) - 1), Block.UPDATE_ALL); // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) + Optional standUpPosition = RespawnAnchorBlock.findStandUpPosition(EntityType.PLAYER, level, pos); + if (!forced && consumeSpawnBlock && standUpPosition.isPresent()) { +- level.setBlock(pos, blockState.setValue(RespawnAnchorBlock.CHARGE, blockState.getValue(RespawnAnchorBlock.CHARGE) - 1), Block.UPDATE_ALL); ++ consumeAnchorCharge = () -> level.setBlock(pos, blockState.setValue(RespawnAnchorBlock.CHARGE, blockState.getValue(RespawnAnchorBlock.CHARGE) - 1), Block.UPDATE_ALL); // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) } + final Runnable finalConsumeAnchorCharge = consumeAnchorCharge; // Paper - Fix SPIGOT-5989 -- return optional.map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, 0.0F)); -+ return optional.map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, 0.0F, false, true, finalConsumeAnchorCharge)); // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) - } else if (block instanceof BedBlock && level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, blockPos).canSetSpawn(level)) { - return BedBlock.findStandUpPosition(EntityType.PLAYER, level, blockPos, blockState.getValue(BedBlock.FACING), yaw) -- .map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, 0.0F)); -+ .map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, 0.0F, true, false, null)); // Paper - Fix SPIGOT-5989 - } else if (!flag) { +- return standUpPosition.map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F)); ++ return standUpPosition.map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F, false, true, finalConsumeAnchorCharge)); // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) + } else if (block instanceof BedBlock && level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos).canSetSpawn(level)) { + return BedBlock.findStandUpPosition(EntityType.PLAYER, level, pos, blockState.getValue(BedBlock.FACING), yaw) +- .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F)); ++ .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F, true, false, null)); // Paper - Fix SPIGOT-5989 + } else if (!forced) { return Optional.empty(); } else { -@@ -1057,7 +_,7 @@ - BlockState blockState1 = level.getBlockState(blockPos.above()); - boolean isPossibleToRespawnInThis1 = blockState1.getBlock().isPossibleToRespawnInThis(blockState1); - return isPossibleToRespawnInThis && isPossibleToRespawnInThis1 -- ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.1, blockPos.getZ() + 0.5), yaw, pitch)) -+ ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.1, blockPos.getZ() + 0.5), yaw, pitch, false, false, null)) // Paper - Fix SPIGOT-5989 +@@ -1080,7 +_,7 @@ + BlockState topState = level.getBlockState(pos.above()); + boolean freeTop = topState.getBlock().isPossibleToRespawnInThis(topState); + return freeBottom && freeTop +- ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(pos.getX() + 0.5, pos.getY() + 0.1, pos.getZ() + 0.5), yaw, pitch)) ++ ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(pos.getX() + 0.5, pos.getY() + 0.1, pos.getZ() + 0.5), yaw, pitch, false, false, null)) // Paper - Fix SPIGOT-5989 : Optional.empty(); } } -@@ -1074,6 +_,7 @@ +@@ -1096,7 +_,8 @@ + } @Override - public @Nullable ServerPlayer teleport(TeleportTransition teleportTransition) { +- public @Nullable ServerPlayer teleport(final TeleportTransition transition) { ++ public @Nullable ServerPlayer teleport(TeleportTransition transition) { // Paper - make non-final + if (this.isSleeping()) return null; // CraftBukkit - SPIGOT-3154 if (this.isRemoved()) { return null; } else { -@@ -1083,13 +_,48 @@ - - ServerLevel level = teleportTransition.newLevel(); - ServerLevel serverLevel = this.level(); -- ResourceKey resourceKey = serverLevel.dimension(); +@@ -1107,12 +_,46 @@ + ServerLevel newLevel = transition.newLevel(); + ServerLevel oldLevel = this.level(); + ResourceKey lastDimension = oldLevel.dimension(); + // CraftBukkit start -+ ResourceKey resourceKey = serverLevel.getTypeKey(); ++ ResourceKey oldLevelTypeKey = oldLevel.getTypeKey(); + + org.bukkit.Location enter = this.getBukkitEntity().getLocation(); -+ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); -+ org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), level, absolutePosition.yRot(), absolutePosition.xRot()); ++ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); ++ org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), newLevel, absolutePosition.yRot(), absolutePosition.xRot()); + final org.bukkit.event.player.PlayerTeleportEvent tpEvent; + // Paper start - gateway-specific teleport event + if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.level().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { + tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.level().getWorld(), theEndGatewayBlockEntity)); + } else { -+ tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), teleportTransition.cause()); ++ tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), transition.cause()); + } + // Paper end - gateway-specific teleport event + org.bukkit.Bukkit.getServer().getPluginManager().callEvent(tpEvent); @@ -769,61 +776,58 @@ + return null; + } + if (!newExit.equals(exit)) { -+ level = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle(); -+ teleportTransition = new TeleportTransition( -+ level, ++ newLevel = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle(); ++ transition = new TeleportTransition( ++ newLevel, + org.bukkit.craftbukkit.util.CraftLocation.toVec3(newExit), + Vec3.ZERO, + newExit.getYaw(), + newExit.getPitch(), -+ teleportTransition.missingRespawnBlock(), -+ teleportTransition.asPassenger(), ++ transition.missingRespawnBlock(), ++ transition.asPassenger(), + Set.of(), -+ teleportTransition.postTeleportTransition(), -+ teleportTransition.cause()); ++ transition.postTeleportTransition(), ++ transition.cause()); + } + // CraftBukkit end - if (!teleportTransition.asPassenger()) { + if (!transition.asPassenger()) { this.removeVehicle(); } -- if (level.dimension() == resourceKey) { -- this.connection.teleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); -+ // CraftBukkit start -+ if (level.dimension() == serverLevel.dimension()) { -+ this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); -+ // CraftBukkit end + if (newLevel.dimension() == lastDimension) { +- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); ++ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit this.connection.resetPosition(); - teleportTransition.postTeleportTransition().onTransition(this); + transition.postTeleportTransition().onTransition(this); return this; -@@ -1100,18 +_,19 @@ +@@ -1123,18 +_,19 @@ this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); PlayerList playerList = this.server.getPlayerList(); playerList.sendPlayerPermissionLevel(this); + this.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds - serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + oldLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); this.unsetRemoved(); - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("moving"); -- if (resourceKey == Level.OVERWORLD && level.dimension() == Level.NETHER) { -+ if (resourceKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event + ProfilerFiller profiler = Profiler.get(); + profiler.push("moving"); +- if (lastDimension == Level.OVERWORLD && newLevel.dimension() == Level.NETHER) { ++ if (oldLevelTypeKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event this.enteredNetherPosition = this.position(); } - profilerFiller.pop(); - profilerFiller.push("placing"); - this.setServerLevel(level); -- this.connection.teleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); -+ this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); // CraftBukkit - use internal teleport without event + profiler.pop(); + profiler.push("placing"); + this.setServerLevel(newLevel); +- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); ++ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit - use internal teleport without event this.connection.resetPosition(); - level.addDuringTeleport(this); - profilerFiller.pop(); -@@ -1126,6 +_,15 @@ + newLevel.addDuringTeleport(this); + profiler.pop(); +@@ -1149,6 +_,15 @@ this.lastSentHealth = -1.0F; this.lastSentFood = -1; - this.teleportSpectators(teleportTransition, serverLevel); + this.teleportSpectators(transition, oldLevel); + // CraftBukkit start -+ org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld()); ++ org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld()); + this.level().getCraftServer().getPluginManager().callEvent(changeEvent); + // CraftBukkit end + // Paper start - Reset shield blocking on dimension change @@ -834,24 +838,24 @@ return this; } } -@@ -1140,12 +_,26 @@ - public void triggerDimensionChangeTriggers(ServerLevel level) { - ResourceKey resourceKey = level.dimension(); - ResourceKey resourceKey1 = this.level().dimension(); -- CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourceKey, resourceKey1); -- if (resourceKey == Level.NETHER && resourceKey1 == Level.OVERWORLD && this.enteredNetherPosition != null) { +@@ -1163,12 +_,26 @@ + public void triggerDimensionChangeTriggers(final ServerLevel oldLevel) { + ResourceKey oldKey = oldLevel.dimension(); + ResourceKey newKey = this.level().dimension(); +- CriteriaTriggers.CHANGED_DIMENSION.trigger(this, oldKey, newKey); +- if (oldKey == Level.NETHER && newKey == Level.OVERWORLD && this.enteredNetherPosition != null) { + // CraftBukkit start -+ ResourceKey maindimensionkey = org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level); ++ ResourceKey maindimensionkey = org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(oldLevel); + ResourceKey maindimensionkey1 = org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(this.level()); + // Paper start - Add option for strict advancement dimension checks + if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck) { -+ maindimensionkey = resourceKey; -+ maindimensionkey1 = resourceKey1; ++ maindimensionkey = oldKey; ++ maindimensionkey1 = newKey; + } + // Paper end - Add option for strict advancement dimension checks + CriteriaTriggers.CHANGED_DIMENSION.trigger(this, maindimensionkey, maindimensionkey1); -+ if (maindimensionkey != resourceKey || maindimensionkey1 != resourceKey1) { -+ CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourceKey, resourceKey1); ++ if (maindimensionkey != oldKey || maindimensionkey1 != newKey) { ++ CriteriaTriggers.CHANGED_DIMENSION.trigger(this, oldKey, newKey); + } + + if (maindimensionkey == Level.NETHER && maindimensionkey1 == Level.OVERWORLD && this.enteredNetherPosition != null) { @@ -859,43 +863,42 @@ CriteriaTriggers.NETHER_TRAVEL.trigger(this, this.enteredNetherPosition); } -- if (resourceKey1 != Level.NETHER) { +- if (newKey != Level.NETHER) { + if (maindimensionkey1 != Level.NETHER) { // CraftBukkit this.enteredNetherPosition = null; } } -@@ -1161,11 +_,12 @@ +@@ -1184,10 +_,12 @@ this.containerMenu.broadcastChanges(); } - @Override -- public Either startSleepInBed(BlockPos bedPos) { -- Direction direction = this.level().getBlockState(bedPos).getValue(HorizontalDirectionalBlock.FACING); +- public Either startSleepInBed(final BlockPos pos) { +- Direction direction = this.level().getBlockState(pos).getValue(HorizontalDirectionalBlock.FACING); - if (!this.isSleeping() && this.isAlive()) { -- BedRule bedRule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, bedPos); + // CraftBukkit start - moved bed result checks from below into separate method -+ private Either getBedResult(BlockPos bedPos, Direction direction) { -+ BedRule bedRule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, bedPos); ++ private Either getBedResult(final BlockPos pos, final Direction direction) { ++ BedRule bedRule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); + if (bedRule.explodes()) { + return Either.left(Player.BedSleepingProblem.EXPLOSION); + } else if (!this.isSleeping() && this.isAlive()) { - boolean canSleep = bedRule.canSleep(this.level()); - boolean canSetSpawn = bedRule.canSetSpawn(this.level()); - if (!canSetSpawn && !canSleep) { -@@ -1177,7 +_,7 @@ + BedRule rule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); + boolean canSleep = rule.canSleep(this.level()); + boolean canSetSpawn = rule.canSetSpawn(this.level()); +@@ -1200,7 +_,7 @@ } else { if (canSetSpawn) { this.setRespawnPosition( -- new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), bedPos, this.getYRot(), this.getXRot()), false), true -+ new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), bedPos, this.getYRot(), this.getXRot()), false), true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED // Paper - Add PlayerSetSpawnEvent +- new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true ++ new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED // Paper - Add PlayerSetSpawnEvent ); } -@@ -1199,7 +_,37 @@ +@@ -1229,7 +_,37 @@ } } -- Either either = super.startSleepInBed(bedPos).ifRight(unit -> { +- Either result = super.startSleepInBed(pos).ifRight(unit -> { + // CraftBukkit start + return Either.right(Unit.INSTANCE); + } @@ -906,9 +909,9 @@ + } + + @Override -+ public Either startSleepInBed(BlockPos bedPos, boolean force) { -+ Direction direction = this.level().getBlockState(bedPos).getValue(HorizontalDirectionalBlock.FACING); -+ Either bedResult = this.getBedResult(bedPos, direction); ++ public Either startSleepInBed(BlockPos pos, boolean force) { ++ Direction direction = this.level().getBlockState(pos).getValue(HorizontalDirectionalBlock.FACING); ++ Either bedResult = this.getBedResult(pos, direction); + + if (bedResult.left().orElse(null) == net.minecraft.world.entity.player.Player.BedSleepingProblem.OTHER_PROBLEM) { + return bedResult; // return immediately if the result is not bypassable by plugins @@ -918,22 +921,22 @@ + bedResult = Either.right(Unit.INSTANCE); + } + -+ bedResult = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedEnterEvent(this, bedPos, bedResult); ++ bedResult = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedEnterEvent(this, pos, bedResult); + if (bedResult.left().isPresent()) { + return bedResult; + } + + { + { -+ Either either = super.startSleepInBed(bedPos, force).ifRight(unit -> { ++ Either result = super.startSleepInBed(pos, force).ifRight(unit -> { + // CraftBukkit end this.awardStat(Stats.SLEEP_IN_BED); CriteriaTriggers.SLEPT_IN_BED.trigger(this); }); -@@ -1209,10 +_,7 @@ +@@ -1239,10 +_,7 @@ this.level().updateSleepingPlayerList(); - return either; + return result; - } } - } else { @@ -941,10 +944,10 @@ } } -@@ -1238,21 +_,29 @@ +@@ -1270,19 +_,30 @@ @Override - public void stopSleepInBed(boolean wakeImmediately, boolean updateLevelForSleepingPlayers) { + public void stopSleepInBed(final boolean forcefulWakeUp, final boolean updateLevelList) { + if (!this.isSleeping()) return; // CraftBukkit - Can't leave bed if not in one! + // CraftBukkit start - fire PlayerBedLeaveEvent + org.bukkit.block.Block bed = org.bukkit.craftbukkit.block.CraftBlock.at(this.level(), this.getSleepingPos().orElse(this.blockPosition())); @@ -957,7 +960,7 @@ this.level().getChunkSource().sendToTrackingPlayersAndSelf(this, new ClientboundAnimatePacket(this, ClientboundAnimatePacket.WAKE_UP)); } - super.stopSleepInBed(wakeImmediately, updateLevelForSleepingPlayers); + super.stopSleepInBed(forcefulWakeUp, updateLevelList); if (this.connection != null) { - this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); + this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.EXIT_BED); // CraftBukkit @@ -965,16 +968,16 @@ } @Override - public boolean isInvulnerableTo(ServerLevel level, DamageSource damageSource) { -- return super.isInvulnerableTo(level, damageSource) -+ return (super.isInvulnerableTo(level, damageSource) // Paper - disable player cramming; - || this.isChangingDimension() && !damageSource.is(DamageTypes.ENDER_PEARL) -- || !this.connection.hasClientLoaded(); -+ || !this.connection.hasClientLoaded()) || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && damageSource.is(DamageTypes.CRAMMING)); // Paper - disable player cramming; + public boolean isInvulnerableTo(final ServerLevel level, final DamageSource source) { +- return super.isInvulnerableTo(level, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.connection.hasClientLoaded(); ++ // Paper start - disable player cramming ++ return (super.isInvulnerableTo(level, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.connection.hasClientLoaded()) ++ || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); ++ // Paper end - disable player cramming } @Override -@@ -1300,8 +_,9 @@ +@@ -1330,8 +_,9 @@ this.connection.send(new ClientboundShowDialogPacket(dialog)); } @@ -985,8 +988,8 @@ } @Override -@@ -1309,12 +_,39 @@ - if (menu == null) { +@@ -1339,12 +_,39 @@ + if (provider == null) { return OptionalInt.empty(); } else { - if (this.containerMenu != this.inventoryMenu) { @@ -995,23 +998,23 @@ } this.nextContainerCounter(); - AbstractContainerMenu abstractContainerMenu = menu.createMenu(this.containerCounter, this.getInventory(), this); + AbstractContainerMenu menu = provider.createMenu(this.containerCounter, this.getInventory(), this); + Component title = null; // Paper - Add titleOverride to InventoryOpenEvent + // CraftBukkit start - Inventory open hook -+ if (abstractContainerMenu != null) { -+ abstractContainerMenu.setTitle(menu.getDisplayName()); ++ if (menu != null) { ++ menu.setTitle(provider.getDisplayName()); + + boolean cancelled = false; + // Paper start - Add titleOverride to InventoryOpenEvent -+ final com.mojang.datafixers.util.Pair result = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEventWithTitle(this, abstractContainerMenu, cancelled); -+ abstractContainerMenu = result.getSecond(); ++ final com.mojang.datafixers.util.Pair result = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEventWithTitle(this, menu, cancelled); ++ menu = result.getSecond(); + title = io.papermc.paper.adventure.PaperAdventure.asVanilla(result.getFirst()); + // Paper end - Add titleOverride to InventoryOpenEvent -+ if (abstractContainerMenu == null && !cancelled) { // Let pre-cancelled events fall through ++ if (menu == null && !cancelled) { // Let pre-cancelled events fall through + // SPIGOT-5263 - close chest if cancelled -+ if (menu instanceof Container container) { ++ if (provider instanceof Container container) { + container.stopOpen(this); -+ } else if (menu instanceof net.minecraft.world.level.block.ChestBlock.DoubleInventory doubleInventory) { ++ } else if (provider instanceof net.minecraft.world.level.block.ChestBlock.DoubleInventory doubleInventory) { + // SPIGOT-5355 - double chests too :( + doubleInventory.container.stopOpen(this); + // Paper start - Fix InventoryOpenEvent cancellation @@ -1023,38 +1026,37 @@ + } + } + // CraftBukkit end - if (abstractContainerMenu == null) { + if (menu == null) { if (this.isSpectator()) { - this.displayClientMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED), true); -@@ -1322,10 +_,14 @@ + this.sendOverlayMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED)); +@@ -1352,9 +_,13 @@ return OptionalInt.empty(); } else { +- this.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), provider.getDisplayName())); + // CraftBukkit start -+ this.containerMenu = abstractContainerMenu; // Moved up ++ this.containerMenu = menu; // Moved up + if (!this.isImmobile()) - this.connection -- .send(new ClientboundOpenScreenPacket(abstractContainerMenu.containerId, abstractContainerMenu.getType(), menu.getDisplayName())); -+ .send(new net.minecraft.network.protocol.game.ClientboundOpenScreenPacket(abstractContainerMenu.containerId, abstractContainerMenu.getType(), java.util.Objects.requireNonNullElseGet(title, abstractContainerMenu::getTitle))); // Paper - Add titleOverride to InventoryOpenEven ++ this.connection.send(new net.minecraft.network.protocol.game.ClientboundOpenScreenPacket(menu.containerId, menu.getType(), java.util.Objects.requireNonNullElseGet(title, menu::getTitle))); // Paper - Add titleOverride to InventoryOpenEven + // CraftBukkit end - this.initMenu(abstractContainerMenu); -- this.containerMenu = abstractContainerMenu; + this.initMenu(menu); +- this.containerMenu = menu; + // CraftBukkit - moved up return OptionalInt.of(this.containerCounter); } } -@@ -1338,27 +_,49 @@ +@@ -1374,27 +_,49 @@ @Override - public void openHorseInventory(AbstractHorse horse, Container inventory) { + public void openHorseInventory(final AbstractHorse horse, final Container container) { + // CraftBukkit start - Inventory open hook + this.nextContainerCounter(); // Moved up from below -+ AbstractContainerMenu container = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse, horse.getInventoryColumns()); -+ container.setTitle(horse.getDisplayName()); -+ container = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEvent(this, container); ++ AbstractContainerMenu menu = new HorseInventoryMenu(this.containerCounter, this.getInventory(), container, horse, horse.getInventoryColumns()); ++ menu.setTitle(horse.getDisplayName()); ++ menu = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEvent(this, menu); + -+ if (container == null) { -+ inventory.stopOpen(this); ++ if (menu == null) { ++ container.stopOpen(this); + return; + } + // CraftBukkit end @@ -1067,21 +1069,21 @@ + // this.nextContainerCounter(); // CraftBukkit - moved up int inventoryColumns = horse.getInventoryColumns(); this.connection.send(new ClientboundMountScreenOpenPacket(this.containerCounter, inventoryColumns, horse.getId())); -- this.containerMenu = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse, inventoryColumns); -+ this.containerMenu = container; // CraftBukkit +- this.containerMenu = new HorseInventoryMenu(this.containerCounter, this.getInventory(), container, horse, inventoryColumns); ++ this.containerMenu = menu; // CraftBukkit this.initMenu(this.containerMenu); } @Override - public void openNautilusInventory(AbstractNautilus nautilus, Container inventory) { + public void openNautilusInventory(final AbstractNautilus nautilus, final Container container) { + // Paper start - Inventory open hook + this.nextContainerCounter(); // moved up from below -+ AbstractContainerMenu menu = new NautilusInventoryMenu(this.containerCounter, this.getInventory(), inventory, nautilus, nautilus.getInventoryColumns()); ++ AbstractContainerMenu menu = new NautilusInventoryMenu(this.containerCounter, this.getInventory(), container, nautilus, nautilus.getInventoryColumns()); + menu.setTitle(nautilus.getDisplayName()); + menu = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEvent(this, menu); + + if (menu == null) { -+ inventory.stopOpen(this); ++ container.stopOpen(this); + return; + } + // Paper end @@ -1093,12 +1095,12 @@ + // this.nextContainerCounter(); Paper - Move Up int inventoryColumns = nautilus.getInventoryColumns(); this.connection.send(new ClientboundMountScreenOpenPacket(this.containerCounter, inventoryColumns, nautilus.getId())); -- this.containerMenu = new NautilusInventoryMenu(this.containerCounter, this.getInventory(), inventory, nautilus, inventoryColumns); +- this.containerMenu = new NautilusInventoryMenu(this.containerCounter, this.getInventory(), container, nautilus, inventoryColumns); + this.containerMenu = menu; // Paper - Moved up declaration this.initMenu(this.containerMenu); } -@@ -1380,10 +_,30 @@ +@@ -1416,10 +_,30 @@ @Override public void closeContainer() { @@ -1129,63 +1131,63 @@ @Override public void doCloseContainer() { this.containerMenu.removed(this); -@@ -1406,19 +_,19 @@ - int rounded = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.SWIM_ONE_CM, rounded); -- this.causeFoodExhaustion(0.01F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.SWIM); // CraftBukkit - EntityExhaustionEvent // Spigot +@@ -1442,19 +_,19 @@ + int distance = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); + if (distance > 0) { + this.awardStat(Stats.SWIM_ONE_CM, distance); +- this.causeFoodExhaustion(0.01F * distance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * distance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent // Spigot } } else if (this.isEyeInFluid(FluidTags.WATER)) { - int rounded = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, rounded); -- this.causeFoodExhaustion(0.01F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_UNDERWATER); // CraftBukkit - EntityExhaustionEvent // Spigot + int distance = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); + if (distance > 0) { + this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, distance); +- this.causeFoodExhaustion(0.01F * distance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * distance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent // Spigot } } else if (this.isInWater()) { - int rounded = Math.round((float)Math.sqrt(dx * dx + dz * dz) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.WALK_ON_WATER_ONE_CM, rounded); -- this.causeFoodExhaustion(0.01F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent // Spigot + int horizontalDistance = Math.round((float)Math.sqrt(dx * dx + dz * dz) * 100.0F); + if (horizontalDistance > 0) { + this.awardStat(Stats.WALK_ON_WATER_ONE_CM, horizontalDistance); +- this.causeFoodExhaustion(0.01F * horizontalDistance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * horizontalDistance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent // Spigot } } else if (this.onClimbable()) { if (dy > 0.0) { -@@ -1429,13 +_,13 @@ - if (rounded > 0) { +@@ -1465,13 +_,13 @@ + if (horizontalDistance > 0) { if (this.isSprinting()) { - this.awardStat(Stats.SPRINT_ONE_CM, rounded); -- this.causeFoodExhaustion(0.1F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.sprintMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.SPRINT); // CraftBukkit - EntityExhaustionEvent // Spigot + this.awardStat(Stats.SPRINT_ONE_CM, horizontalDistance); +- this.causeFoodExhaustion(0.1F * horizontalDistance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.sprintMultiplier * horizontalDistance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent // Spigot } else if (this.isCrouching()) { - this.awardStat(Stats.CROUCH_ONE_CM, rounded); -- this.causeFoodExhaustion(0.0F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.CROUCH); // CraftBukkit - EntityExhaustionEvent // Spigot + this.awardStat(Stats.CROUCH_ONE_CM, horizontalDistance); +- this.causeFoodExhaustion(0.0F * horizontalDistance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * horizontalDistance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.CROUCH); // CraftBukkit - EntityExhaustionEvent // Spigot } else { - this.awardStat(Stats.WALK_ONE_CM, rounded); -- this.causeFoodExhaustion(0.0F * rounded * 0.01F); -+ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent // Spigot + this.awardStat(Stats.WALK_ONE_CM, horizontalDistance); +- this.causeFoodExhaustion(0.0F * horizontalDistance * 0.01F); ++ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * horizontalDistance * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent // Spigot } } } else if (this.isFallFlying()) { -@@ -1479,13 +_,13 @@ +@@ -1515,13 +_,13 @@ @Override - public void awardStat(Stat stat, int amount) { - this.stats.increment(this, stat, amount); -- this.level().getScoreboard().forAllObjectives(stat, this, score -> score.add(amount)); -+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, scoreAccess -> scoreAccess.add(amount)); // CraftBukkit - Get our scores instead + public void awardStat(final Stat stat, final int count) { + this.stats.increment(this, stat, count); +- this.level().getScoreboard().forAllObjectives(stat, this, score -> score.add(count)); ++ this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, score -> score.add(count)); // CraftBukkit - Get our scores instead } @Override - public void resetStat(Stat stat) { + public void resetStat(final Stat stat) { this.stats.setValue(this, stat, 0); - this.level().getScoreboard().forAllObjectives(stat, this, ScoreAccess::reset); + this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, ScoreAccess::reset); // CraftBukkit - Get our scores instead } @Override -@@ -1516,9 +_,9 @@ +@@ -1552,9 +_,9 @@ super.jumpFromGround(); this.awardStat(Stats.JUMP); if (this.isSprinting()) { @@ -1197,7 +1199,7 @@ } } -@@ -1533,6 +_,13 @@ +@@ -1569,6 +_,13 @@ public void disconnect() { this.disconnected = true; this.ejectPassengers(); @@ -1211,7 +1213,7 @@ if (this.isSleeping()) { this.stopSleepInBed(true, false); } -@@ -1544,6 +_,7 @@ +@@ -1580,6 +_,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; @@ -1219,38 +1221,38 @@ } @Override -@@ -1578,18 +_,18 @@ +@@ -1609,18 +_,18 @@ this.onUpdateAbilities(); - this.getAttributes().assignBaseValues(that.getAttributes()); - if (keepEverything) { -- this.getAttributes().assignPermanentModifiers(that.getAttributes()); -+ // this.getAttributes().assignPermanentModifiers(that.getAttributes()); // CraftBukkit - this.setHealth(that.getHealth()); - this.foodData = that.foodData; - - for (MobEffectInstance mobEffectInstance : that.getActiveEffects()) { -- this.addEffect(new MobEffectInstance(mobEffectInstance)); -+ // this.addEffect(new MobEffectInstance(mobEffectInstance)); // CraftBukkit + this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); + if (restoreAll) { +- this.getAttributes().assignPermanentModifiers(oldPlayer.getAttributes()); ++ // this.getAttributes().assignPermanentModifiers(oldPlayer.getAttributes()); // CraftBukkit + this.setHealth(oldPlayer.getHealth()); + this.foodData = oldPlayer.foodData; + + for (MobEffectInstance effect : oldPlayer.getActiveEffects()) { +- this.addEffect(new MobEffectInstance(effect)); ++ // this.addEffect(new MobEffectInstance(effect)); // CraftBukkit } - this.transferInventoryXpAndScore(that); - this.portalProcess = that.portalProcess; + this.transferInventoryXpAndScore(oldPlayer); + this.portalProcess = oldPlayer.portalProcess; } else { - this.setHealth(this.getMaxHealth()); + // this.setHealth(this.getMaxHealth()); // CraftBukkit - if (this.level().getGameRules().get(GameRules.KEEP_INVENTORY) || that.isSpectator()) { - this.transferInventoryXpAndScore(that); + if (this.level().getGameRules().get(GameRules.KEEP_INVENTORY) || oldPlayer.isSpectator()) { + this.transferInventoryXpAndScore(oldPlayer); } -@@ -1601,7 +_,7 @@ +@@ -1632,7 +_,7 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; -- this.recipeBook.copyOverData(that.recipeBook); -+ // this.recipeBook.copyOverData(that.recipeBook); // CraftBukkit - this.seenCredits = that.seenCredits; - this.enteredNetherPosition = that.enteredNetherPosition; - this.chunkTrackingView = that.chunkTrackingView; -@@ -1653,9 +_,22 @@ +- this.recipeBook.copyOverData(oldPlayer.recipeBook); ++ // this.recipeBook.copyOverData(oldPlayer.recipeBook); // CraftBukkit + this.seenCredits = oldPlayer.seenCredits; + this.enteredNetherPosition = oldPlayer.enteredNetherPosition; + this.chunkTrackingView = oldPlayer.chunkTrackingView; +@@ -1684,9 +_,22 @@ CriteriaTriggers.EFFECTS_CHANGED.trigger(this, null); } @@ -1262,58 +1264,57 @@ + // Paper end - use dismount cause + @Override - public void teleportTo(double x, double y, double z) { + public void teleportTo(final double x, final double y, final double z) { - this.connection.teleport(new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, 0.0F, 0.0F), Relative.union(Relative.DELTA, Relative.ROTATION)); + // Paper start - pass cause + this.teleportTo(x, y, z, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + -+ public void teleportTo(double x, double y, double z, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { ++ public void teleportTo(final double x, final double y, final double z, final org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { + this.connection.teleport(new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, 0.0F, 0.0F), Relative.union(Relative.DELTA, Relative.ROTATION), cause); + // Paper end - pass cause } @Override -@@ -1664,7 +_,7 @@ - } - - @Override -- public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera) { -+ public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { // CraftBukkit +@@ -1704,6 +_,7 @@ + final float newYRot, + final float newXRot, + final boolean resetCamera ++ , final org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause // CraftBukkit + ) { if (this.isSleeping()) { this.stopSleepInBed(true, true); - } -@@ -1673,7 +_,7 @@ +@@ -1713,7 +_,7 @@ this.setCamera(this); } -- boolean flag = super.teleportTo(level, x, y, z, relativeMovements, yaw, pitch, setCamera); -+ boolean flag = super.teleportTo(level, x, y, z, relativeMovements, yaw, pitch, setCamera, cause); // CraftBukkit - if (flag) { - this.setYHeadRot(relativeMovements.contains(Relative.Y_ROT) ? this.getYHeadRot() + yaw : yaw); +- boolean success = super.teleportTo(level, x, y, z, relatives, newYRot, newXRot, resetCamera); ++ boolean success = super.teleportTo(level, x, y, z, relatives, newYRot, newXRot, resetCamera, cause); // CraftBukkit + if (success) { + this.setYHeadRot(relatives.contains(Relative.Y_ROT) ? this.getYHeadRot() + newYRot : newYRot); this.connection.resetFlyingTicks(); -@@ -1712,9 +_,18 @@ +@@ -1752,9 +_,18 @@ } - public boolean setGameMode(GameType gameMode) { + public boolean setGameMode(final GameType mode) { + // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.setGameMode(mode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); + return event != null && !event.isCancelled(); + } -+ public org.bukkit.event.player.@Nullable PlayerGameModeChangeEvent setGameMode(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, net.kyori.adventure.text.@Nullable Component message) { - boolean isSpectator = this.isSpectator(); -- if (!this.gameMode.changeGameModeForPlayer(gameMode)) { ++ public org.bukkit.event.player.@Nullable PlayerGameModeChangeEvent setGameMode(final GameType mode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, net.kyori.adventure.text.@Nullable Component message) { + boolean wasSpectator = this.isSpectator(); +- if (!this.gameMode.changeGameModeForPlayer(mode)) { - return false; -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(gameMode, cause, message); ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(mode, cause, message); + if (event == null) { + return null; + } else if (event.isCancelled()) { + return event; // need to return the event for the cancel message + // Paper end - Expand PlayerGameModeChangeEvent } else { - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId())); - if (gameMode == GameType.SPECTATOR) { -@@ -1731,7 +_,7 @@ + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, mode.getId())); + if (mode == GameType.SPECTATOR) { +@@ -1771,7 +_,7 @@ this.onUpdateAbilities(); this.updateEffectVisibility(); @@ -1322,90 +1323,90 @@ } } -@@ -1786,8 +_,13 @@ +@@ -1840,8 +_,13 @@ } - public void sendChatMessage(OutgoingChatMessage message, boolean filtered, ChatType.Bound boundChatType) { + public void sendChatMessage(final OutgoingChatMessage message, final boolean filtered, final ChatType.Bound chatType) { + // Paper start -+ this.sendChatMessage(message, filtered, boundChatType, null); ++ this.sendChatMessage(message, filtered, chatType, null); + } -+ public void sendChatMessage(OutgoingChatMessage message, boolean filtered, ChatType.Bound boundChatType, @Nullable Component unsigned) { ++ public void sendChatMessage(final OutgoingChatMessage message, final boolean filtered, final ChatType.Bound chatType, @Nullable Component unsigned) { + // Paper end if (this.acceptsChatMessages()) { -- message.sendToPlayer(this, filtered, boundChatType); -+ message.sendToPlayer(this, filtered, boundChatType, unsigned); // Paper +- message.sendToPlayer(this, filtered, chatType); ++ message.sendToPlayer(this, filtered, chatType, unsigned); // Paper } } -@@ -1798,7 +_,42 @@ +@@ -1852,7 +_,42 @@ } - public void updateOptions(ClientInformation clientInformation) { + public void updateOptions(final ClientInformation information) { + // Paper start - settings event + new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(this.getBukkitEntity(), Util.make(new java.util.IdentityHashMap<>(), map -> { -+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, clientInformation.language()); -+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, clientInformation.viewDistance()); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientInformation.chatVisibility().name())); -+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, clientInformation.chatColors()); -+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(clientInformation.modelCustomisation())); -+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, clientInformation.mainHand() == net.minecraft.world.entity.HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT); -+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, clientInformation.textFilteringEnabled()); -+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, clientInformation.allowsListing()); -+ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(clientInformation.particleStatus().name())); ++ map.put(com.destroystokyo.paper.ClientOption.LOCALE, information.language()); ++ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, information.viewDistance()); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(information.chatVisibility().name())); ++ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, information.chatColors()); ++ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(information.modelCustomisation())); ++ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, information.mainHand() == net.minecraft.world.entity.HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT); ++ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, information.textFilteringEnabled()); ++ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, information.allowsListing()); ++ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(information.particleStatus().name())); + })).callEvent(); + // Paper end - settings event + // CraftBukkit start -+ if (this.getMainArm() != clientInformation.mainHand()) { ++ if (this.getMainArm() != information.mainHand()) { + org.bukkit.event.player.PlayerChangedMainHandEvent event = new org.bukkit.event.player.PlayerChangedMainHandEvent( + this.getBukkitEntity(), -+ clientInformation.mainHand() == net.minecraft.world.entity.HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT ++ information.mainHand() == net.minecraft.world.entity.HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT + ); -+ this.server.server.getPluginManager().callEvent(event); ++ event.callEvent(); + } -+ if (this.language == null || !this.language.equals(clientInformation.language())) { // Paper ++ if (this.language == null || !this.language.equals(information.language())) { // Paper + org.bukkit.event.player.PlayerLocaleChangeEvent event = new org.bukkit.event.player.PlayerLocaleChangeEvent( + this.getBukkitEntity(), -+ clientInformation.language() ++ information.language() + ); -+ this.server.server.getPluginManager().callEvent(event); ++ event.callEvent(); + } + // CraftBukkit end + // Paper start - don't call options events on login -+ this.updateOptionsNoEvents(clientInformation); ++ this.updateOptionsNoEvents(information); + } -+ public void updateOptionsNoEvents(ClientInformation clientInformation) { ++ public void updateOptionsNoEvents(final ClientInformation information) { + // Paper end - this.language = clientInformation.language(); + this.language = information.language(); + this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper - this.requestedViewDistance = clientInformation.viewDistance(); - this.chatVisibility = clientInformation.chatVisibility(); - this.canChatColor = clientInformation.chatColors(); -@@ -1883,8 +_,23 @@ - Entity camera = this.getCamera(); - this.camera = (Entity)(entityToSpectate == null ? this : entityToSpectate); - if (camera != this.camera) { + this.requestedViewDistance = information.viewDistance(); + this.chatVisibility = information.chatVisibility(); + this.canChatColor = information.chatColors(); +@@ -1937,8 +_,23 @@ + Entity oldCamera = this.getCamera(); + this.camera = (Entity)(newCamera == null ? this : newCamera); + if (oldCamera != this.camera) { + // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity + if (this.camera == this) { + com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), camera.getBukkitEntity()); + if (!playerStopSpectatingEntityEvent.callEvent()) { -+ this.camera = camera; // rollback camera entity again ++ this.camera = oldCamera; // rollback camera entity again + return; + } + } else { -+ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), camera.getBukkitEntity(), entityToSpectate.getBukkitEntity()); ++ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), camera.getBukkitEntity(), newCamera.getBukkitEntity()); + if (!playerStartSpectatingEntityEvent.callEvent()) { -+ this.camera = camera; // rollback camera entity again ++ this.camera = oldCamera; // rollback camera entity again + return; + } + } + // Paper end - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity - if (this.camera.level() instanceof ServerLevel serverLevel) { -- this.teleportTo(serverLevel, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), false); -+ this.teleportTo(serverLevel, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), false, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit + if (this.camera.level() instanceof ServerLevel level) { +- this.teleportTo(level, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), false); ++ this.teleportTo(level, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), false, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit } - if (entityToSpectate != null) { -@@ -1917,11 +_,11 @@ + if (newCamera != null) { +@@ -1962,11 +_,11 @@ } public @Nullable Component getTabListDisplayName() { @@ -1419,21 +1420,21 @@ } @Override -@@ -1951,11 +_,60 @@ +@@ -1996,11 +_,60 @@ } - public void setRespawnPosition(ServerPlayer.@Nullable RespawnConfig respawnConfig, boolean displayInChat) { -- if (displayInChat && respawnConfig != null && !respawnConfig.isSamePosition(this.respawnConfig)) { + public void setRespawnPosition(final ServerPlayer.@Nullable RespawnConfig respawnConfig, final boolean showMessage) { +- if (showMessage && respawnConfig != null && !respawnConfig.isSamePosition(this.respawnConfig)) { - this.sendSystemMessage(SPAWN_SET_MESSAGE); + // Paper start - Add PlayerSetSpawnEvent -+ this.setRespawnPosition(respawnConfig, displayInChat, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.UNKNOWN); ++ this.setRespawnPosition(respawnConfig, showMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.UNKNOWN); + } + -+ public boolean setRespawnPosition(ServerPlayer.@Nullable RespawnConfig respawnConfig, boolean displayInChat, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause cause) { ++ public boolean setRespawnPosition(ServerPlayer.@Nullable RespawnConfig respawnConfig, final boolean showMessage, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause cause) { + org.bukkit.Location spawnLoc = null; + boolean actuallyDisplayInChat = false; + if (respawnConfig != null) { -+ actuallyDisplayInChat = displayInChat && !respawnConfig.isSamePosition(this.respawnConfig); ++ actuallyDisplayInChat = showMessage && !respawnConfig.isSamePosition(this.respawnConfig); + spawnLoc = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(respawnConfig.respawnData().pos(), this.server.getLevel(respawnConfig.respawnData().dimension())); + spawnLoc.setYaw(respawnConfig.respawnData().yaw()); + spawnLoc.setPitch(respawnConfig.respawnData().pitch()); @@ -1482,90 +1483,90 @@ } public SectionPos getLastSectionPos() { -@@ -1975,16 +_,23 @@ +@@ -2020,16 +_,23 @@ } @Override -- public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem) { -- ItemEntity itemEntity = super.drop(droppedItem, dropAround, traceItem); -+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem, boolean callEvent, java.util.function.@Nullable Consumer entityOperation) { // Paper - Extend dropItem API -+ ItemEntity itemEntity = super.drop(droppedItem, dropAround, traceItem, callEvent, entityOperation); // Paper - Extend dropItem API -+ ItemStack itemStack = itemEntity != null ? itemEntity.getItem() : ItemStack.EMPTY; // Paper - move up - if (traceItem) { -- ItemStack itemStack = itemEntity != null ? itemEntity.getItem() : ItemStack.EMPTY; - if (!itemStack.isEmpty()) { -- this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), droppedItem.getCount()); -+ this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), itemStack.getCount()); // Paper - use size from dropped item +- public ItemEntity drop(final ItemStack itemStack, final boolean randomly, final boolean thrownFromHand) { +- ItemEntity entity = super.drop(itemStack, randomly, thrownFromHand); ++ public ItemEntity drop(final ItemStack itemStack, final boolean randomly, final boolean thrownFromHand, final boolean callEvent, final java.util.function.@Nullable Consumer entityOperation) { // Paper - Extend dropItem API ++ ItemEntity entity = super.drop(itemStack, randomly, thrownFromHand, callEvent, entityOperation); // Paper - Extend dropItem API ++ ItemStack droppedItemStack = entity != null ? entity.getItem() : ItemStack.EMPTY; // Paper - move up + if (thrownFromHand) { +- ItemStack droppedItemStack = entity != null ? entity.getItem() : ItemStack.EMPTY; + if (!droppedItemStack.isEmpty()) { +- this.awardStat(Stats.ITEM_DROPPED.get(droppedItemStack.getItem()), itemStack.getCount()); ++ this.awardStat(Stats.ITEM_DROPPED.get(droppedItemStack.getItem()), droppedItemStack.getCount()); // Paper - use size from dropped item this.awardStat(Stats.DROP); } } - + // Paper start - remove player from map on drop -+ if (itemStack.is(net.minecraft.world.item.Items.FILLED_MAP)) { -+ final MapItemSavedData mapData = MapItem.getSavedData(itemStack, this.level()); ++ if (droppedItemStack.is(net.minecraft.world.item.Items.FILLED_MAP)) { ++ final MapItemSavedData mapData = MapItem.getSavedData(droppedItemStack, this.level()); + if (mapData != null) { -+ mapData.tickCarriedBy(this, itemStack); ++ mapData.tickCarriedBy(this, droppedItemStack, null); + } + } + // Paper end - remove player from map on drop - return itemEntity; + return entity; } -@@ -2036,7 +_,7 @@ - super.updateUsingItem(usingItem); +@@ -2081,7 +_,7 @@ + super.updateUsingItem(useItem); } -- public void drop(boolean dropStack) { -+ public boolean drop(boolean dropStack) { // Paper - add back success return +- public void drop(final boolean all) { ++ public boolean drop(final boolean all) { // Paper - add back success return Inventory inventory = this.getInventory(); - ItemStack itemStack = inventory.removeFromSelected(dropStack); + ItemStack removed = inventory.removeFromSelected(all); this.containerMenu -@@ -2046,7 +_,7 @@ +@@ -2091,7 +_,7 @@ this.stopUsingItem(); } -- this.drop(itemStack, false, true); -+ return this.drop(itemStack, false, true) != null; // Paper - add back success return +- this.drop(removed, false, true); ++ return this.drop(removed, false, true) != null; // Paper - add back success return } @Override -@@ -2109,9 +_,9 @@ +@@ -2154,9 +_,9 @@ } @Override - public void removeVehicle() { + public void removeVehicle(final boolean suppressCancellation) { // Paper - Force entity dismount during teleportation - Entity vehicle = this.getVehicle(); + Entity oldVehicle = this.getVehicle(); - super.removeVehicle(); + super.removeVehicle(suppressCancellation); // Paper - Force entity dismount during teleportation - if (vehicle instanceof LivingEntity livingEntity) { - for (MobEffectInstance mobEffectInstance : livingEntity.getActiveEffects()) { - this.connection.send(new ClientboundRemoveMobEffectPacket(vehicle.getId(), mobEffectInstance.getEffect())); -@@ -2233,7 +_,7 @@ + if (oldVehicle instanceof LivingEntity livingEntity) { + for (MobEffectInstance effect : livingEntity.getActiveEffects()) { + this.connection.send(new ClientboundRemoveMobEffectPacket(oldVehicle.getId(), effect.getEffect())); +@@ -2278,7 +_,7 @@ } - public static long placeEnderPearlTicket(ServerLevel level, ChunkPos pos) { -- level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, pos, 2); -+ if (!level.paperConfig().misc.legacyEnderPearlBehavior) level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, pos, 2); // Paper - Allow using old ender pearl behavior + public static long placeEnderPearlTicket(final ServerLevel level, final ChunkPos chunk) { +- level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, chunk, 2); ++ if (!level.paperConfig().misc.legacyEnderPearlBehavior) level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, chunk, 2); // Paper - Allow using old ender pearl behavior return TicketType.ENDER_PEARL.timeout(); } -@@ -2263,9 +_,11 @@ +@@ -2308,9 +_,11 @@ } } - public record RespawnPosAngle(Vec3 position, float yaw, float pitch) { -- public static ServerPlayer.RespawnPosAngle of(Vec3 position, BlockPos towardsPos, float pitch) { -- return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, towardsPos), pitch); +- public static ServerPlayer.RespawnPosAngle of(final Vec3 position, final BlockPos lookAtBlockPos, final float pitch) { +- return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, lookAtBlockPos), pitch); + // CraftBukkit start + public record RespawnPosAngle(Vec3 position, float yaw, float pitch, boolean isBedSpawn, boolean isAnchorSpawn, @Nullable Runnable consumeAnchorCharge) { -+ public static ServerPlayer.RespawnPosAngle of(Vec3 position, BlockPos towardsPos, float pitch, boolean isBedSpawn, boolean isAnchorSpawn, @Nullable Runnable consumeAnchorCharge) { -+ return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, towardsPos), pitch, isBedSpawn, isAnchorSpawn, consumeAnchorCharge); ++ public static ServerPlayer.RespawnPosAngle of(final Vec3 position, final BlockPos lookAtBlockPos, final float pitch, final boolean isBedSpawn, final boolean isAnchorSpawn, final @Nullable Runnable consumeAnchorCharge) { ++ return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, lookAtBlockPos), pitch, isBedSpawn, isAnchorSpawn, consumeAnchorCharge); + // CraftBukkit end } - private static float calculateLookAtYaw(Vec3 position, BlockPos towardsPos) { -@@ -2285,4 +_,135 @@ + private static float calculateLookAtYaw(final Vec3 position, final BlockPos lookAtBlockPos) { +@@ -2330,4 +_,135 @@ ); public static final ServerPlayer.SavedPosition EMPTY = new ServerPlayer.SavedPosition(Optional.empty(), Optional.empty(), Optional.empty()); } @@ -1577,10 +1578,10 @@ + public long getPlayerTime() { + if (this.relativeTime) { + // Adds timeOffset to the current server time. -+ return this.level().getDayTime() + this.timeOffset; ++ return this.level().getDefaultClockTime() + this.timeOffset; + } else { + // Adds timeOffset to the beginning of this day. -+ return this.level().getDayTime() - (this.level().getDayTime() % 24000) + this.timeOffset; ++ return this.level().getDefaultClockTime() - (this.level().getDefaultClockTime() % net.minecraft.SharedConstants.TICKS_PER_GAME_DAY) + this.timeOffset; + } + } + @@ -1642,7 +1643,7 @@ + + public void resetPlayerWeather() { + this.weatherType = null; -+ this.setPlayerWeather(this.level().getLevelData().isRaining() ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.WeatherType.CLEAR, false); ++ this.setPlayerWeather(this.level().isRaining() ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.WeatherType.CLEAR, false); + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch index 700dee35c478..e05a0ec589bb 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -7,19 +7,19 @@ + public boolean captureSentBlockEntities = false; // Paper - Send block entities after destroy prediction + public boolean capturedBlockEntity = false; // Paper - Send block entities after destroy prediction - public ServerPlayerGameMode(ServerPlayer player) { + public ServerPlayerGameMode(final ServerPlayer player) { this.player = player; this.level = player.level(); } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - public boolean changeGameModeForPlayer(GameType gameModeForPlayer) { + public boolean changeGameModeForPlayer(final GameType gameModeForPlayer) { + // Paper start - Expand PlayerGameModeChangeEvent + org.bukkit.event.player.PlayerGameModeChangeEvent event = this.changeGameModeForPlayer(gameModeForPlayer, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null); + return event != null && !event.isCancelled(); + } + -+ public org.bukkit.event.player.@Nullable PlayerGameModeChangeEvent changeGameModeForPlayer(GameType gameModeForPlayer, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause playerGameModeChangeCause, net.kyori.adventure.text.@Nullable Component cancelMessage) { ++ public org.bukkit.event.player.@Nullable PlayerGameModeChangeEvent changeGameModeForPlayer(final GameType gameModeForPlayer, final org.bukkit.event.player.PlayerGameModeChangeEvent.Cause playerGameModeChangeCause, final net.kyori.adventure.text.@Nullable Component cancelMessage) { + // Paper end - Expand PlayerGameModeChangeEvent if (gameModeForPlayer == this.gameModeForPlayer) { - return false; @@ -69,7 +69,7 @@ + if (blockState == null || blockState.isAir()) { // Paper - Don't allow digging into unloaded chunks this.hasDelayedDestroy = false; } else { - float f = this.incrementDestroyProgress(blockState, this.delayedDestroyPos, this.delayedTickStart); + float destroyProgress = this.incrementDestroyProgress(blockState, this.delayedDestroyPos, this.delayedTickStart); @@ -118,7 +_,13 @@ } } @@ -85,20 +85,20 @@ if (blockState.isAir()) { this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); this.lastSentState = -1; -@@ -149,6 +_,7 @@ - - public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction face, int maxBuildHeight, int sequence) { +@@ -151,6 +_,7 @@ + final BlockPos pos, final ServerboundPlayerActionPacket.Action action, final Direction direction, final int maxY, final int sequence + ) { if (!this.player.isWithinBlockInteractionRange(pos, 1.0)) { + if (true) return; // Paper - Don't allow digging into unloaded chunks; Don't notify if unreasonably far away this.debugLogging(pos, false, sequence, "too far"); - } else if (pos.getY() > maxBuildHeight) { + } else if (pos.getY() > maxY) { this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); -@@ -156,16 +_,35 @@ - } else { - if (action == ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK) { +@@ -164,16 +_,35 @@ + } + if (!this.level.mayInteract(this.player, pos)) { + // CraftBukkit start - fire PlayerInteractEvent -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(this.player, org.bukkit.event.block.Action.LEFT_CLICK_BLOCK, pos, face, this.player.getInventory().getSelectedItem(), InteractionHand.MAIN_HAND); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(this.player, org.bukkit.event.block.Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelectedItem(), InteractionHand.MAIN_HAND); this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); this.debugLogging(pos, false, sequence, "may not interact"); - return; @@ -109,7 +109,7 @@ + } + + // CraftBukkit start -+ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(this.player, org.bukkit.event.block.Action.LEFT_CLICK_BLOCK, pos, face, this.player.getInventory().getSelectedItem(), InteractionHand.MAIN_HAND); ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(this.player, org.bukkit.event.block.Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelectedItem(), InteractionHand.MAIN_HAND); + if (event.isCancelled()) { + this.capturedBlockEntity = true; // Paper - Send block entities after destroy prediction + return; @@ -131,17 +131,17 @@ if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); this.debugLogging(pos, false, sequence, "block action restricted"); -@@ -175,7 +_,7 @@ +@@ -183,7 +_,7 @@ this.destroyProgressStart = this.gameTicks; - float f = 1.0F; + float progress = 1.0F; BlockState blockState = this.level.getBlockState(pos); - if (!blockState.isAir()) { + if (event.useInteractedBlock() != org.bukkit.event.Event.Result.DENY && !blockState.isAir()) { // Paper EnchantmentHelper.onHitBlock( this.level, this.player.getMainHandItem(), -@@ -190,6 +_,23 @@ - f = blockState.getDestroyProgress(this.player, this.player.level(), pos); +@@ -198,6 +_,23 @@ + progress = blockState.getDestroyProgress(this.player, this.player.level(), pos); } + // CraftBukkit start @@ -150,21 +150,21 @@ + return; + } + -+ org.bukkit.event.block.BlockDamageEvent blockEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageEvent(this.player, pos, face, this.player.getInventory().getSelectedItem(), f >= 1.0f); // Paper - Add BlockFace to BlockDamageEvent ++ org.bukkit.event.block.BlockDamageEvent blockEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageEvent(this.player, pos, direction, this.player.getInventory().getSelectedItem(), progress >= 1.0f); // Paper - Add BlockFace to BlockDamageEvent + + if (blockEvent.isCancelled()) { + return; + } + + if (blockEvent.getInstaBreak()) { -+ f = 2.0f; ++ progress = 2.0f; + } + // CraftBukkit end + - if (!blockState.isAir() && f >= 1.0F) { + if (!blockState.isAir() && progress >= 1.0F) { this.destroyAndAck(pos, sequence, "insta mine"); } else { -@@ -230,14 +_,22 @@ +@@ -238,14 +_,22 @@ this.debugLogging(pos, true, sequence, "stopped destroying"); } else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) { this.isDestroyingBlock = false; @@ -173,8 +173,8 @@ + // Paper start - Don't allow digging into unloaded chunks + if (!Objects.equals(this.destroyPos, pos) && !BlockPos.ZERO.equals(this.destroyPos)) { // Paper + ServerPlayerGameMode.LOGGER.debug("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); // CraftBukkit - SPIGOT-5457 sent by client when interact event cancelled -+ BlockState type = this.level.getBlockStateIfLoaded(this.destroyPos); // Don't load unloaded chunks for stale records here -+ if (type != null) { ++ BlockState destroyState = this.level.getBlockStateIfLoaded(this.destroyPos); // Don't load unloaded chunks for stale records here ++ if (destroyState != null) { this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); this.debugLogging(pos, true, sequence, "aborted mismatched destroying"); + } @@ -189,17 +189,17 @@ } } } -@@ -253,17 +_,64 @@ +@@ -261,17 +_,62 @@ - public boolean destroyBlock(BlockPos pos) { - BlockState blockState = this.level.getBlockState(pos); -- if (!this.player.getMainHandItem().canDestroyBlock(blockState, this.level, pos, this.player)) { + public boolean destroyBlock(final BlockPos pos) { + BlockState state = this.level.getBlockState(pos); +- if (!this.player.getMainHandItem().canDestroyBlock(state, this.level, pos, this.player)) { + // CraftBukkit start - fire BlockBreakEvent + org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level, pos); + org.bukkit.event.block.BlockBreakEvent event = null; + if (this.player instanceof ServerPlayer) { + // Sword + Creative mode pre-cancel -+ boolean canAttackBlock = !this.player.getMainHandItem().canDestroyBlock(blockState, this.level, pos, this.player); ++ boolean canAttackBlock = !this.player.getMainHandItem().canDestroyBlock(state, this.level, pos, this.player); + event = new org.bukkit.event.block.BlockBreakEvent(bblock, this.player.getBukkitEntity()); + + // Sword + Creative mode pre-cancel @@ -214,9 +214,7 @@ + event.setExpToDrop(block.getExpDrop(updatedBlockState, this.level, pos, itemInHand, true)); + } + -+ this.level.getCraftServer().getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { ++ if (!event.callEvent()) { + if (canAttackBlock) { + return false; + } @@ -235,29 +233,29 @@ + } + // CraftBukkit end + -+ if (false && !this.player.getMainHandItem().canDestroyBlock(blockState, this.level, pos, this.player)) { // CraftBukkit - false ++ if (false && !this.player.getMainHandItem().canDestroyBlock(state, this.level, pos, this.player)) { // CraftBukkit - false return false; } else { -+ blockState = this.level.getBlockState(pos); // CraftBukkit - update state from plugins -+ if (blockState.isAir()) return false; // CraftBukkit - A plugin set block to air without cancelling ++ state = this.level.getBlockState(pos); // CraftBukkit - update state from plugins ++ if (state.isAir()) return false; // CraftBukkit - A plugin set block to air without cancelling BlockEntity blockEntity = this.level.getBlockEntity(pos); - Block block = blockState.getBlock(); + Block block = state.getBlock(); - if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) { + if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission - this.level.sendBlockUpdated(pos, blockState, blockState, Block.UPDATE_ALL); + this.level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL); return false; } else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { return false; } else { + // CraftBukkit start -+ org.bukkit.block.BlockState state = bblock.getState(); ++ org.bukkit.block.BlockState bState = bblock.getState(); + this.level.captureDrops = new java.util.ArrayList<>(); + // CraftBukkit end - BlockState blockState1 = block.playerWillDestroy(this.level, pos, blockState, this.player); - boolean flag = this.level.removeBlock(pos, false); + BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player); + boolean changed = this.level.removeBlock(pos, false); if (SharedConstants.DEBUG_BLOCK_BREAK) { -@@ -274,19 +_,44 @@ - block.destroy(this.level, pos, blockState1); +@@ -282,19 +_,44 @@ + block.destroy(this.level, pos, adjustedState); } + ItemStack mainHandStack = null; // Paper - Trigger bee_nest_destroyed trigger in the correct place @@ -266,20 +264,20 @@ - return true; + // return true; // CraftBukkit } else { - ItemStack mainHandItem = this.player.getMainHandItem(); - ItemStack itemStack = mainHandItem.copy(); - boolean hasCorrectToolForDrops = this.player.hasCorrectToolForDrops(blockState1); -+ mainHandStack = itemStack; // Paper - Trigger bee_nest_destroyed trigger in the correct place -+ isCorrectTool = hasCorrectToolForDrops; // Paper - Trigger bee_nest_destroyed trigger in the correct place - mainHandItem.mineBlock(this.level, blockState1, pos, this.player); -- if (flag && hasCorrectToolForDrops) { -- block.playerDestroy(this.level, this.player, pos, blockState1, blockEntity, itemStack); + ItemStack itemStack = this.player.getMainHandItem(); + ItemStack destroyedWith = itemStack.copy(); + boolean canDestroy = this.player.hasCorrectToolForDrops(adjustedState); ++ mainHandStack = destroyedWith; // Paper - Trigger bee_nest_destroyed trigger in the correct place ++ isCorrectTool = canDestroy; // Paper - Trigger bee_nest_destroyed trigger in the correct place + itemStack.mineBlock(this.level, adjustedState, pos, this.player); +- if (changed && canDestroy) { +- block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith); - } - - return true; - } -+ if (flag && hasCorrectToolForDrops) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion -+ block.playerDestroy(this.level, this.player, pos, blockState1, blockEntity, itemStack, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion ++ if (changed && canDestroy) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion ++ block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion + } + + // return true; // CraftBukkit @@ -288,17 +286,17 @@ + java.util.List itemsToDrop = this.level.captureDrops; // Paper - capture all item additions to the world + this.level.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff + if (event.isDropItems()) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bState, this.player, itemsToDrop); // Paper - capture all item additions to the world + } + + // Drop event experience -+ if (flag) { -+ blockState.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper ++ if (changed) { ++ state.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper + } + // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy) + if (mainHandStack != null) { -+ if (flag && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && blockEntity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above -+ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, blockState, mainHandStack, beehiveBlockEntity.getOccupantCount()); ++ if (changed && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && blockEntity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above ++ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, state, mainHandStack, beehiveBlockEntity.getOccupantCount()); + } + } + // Paper end - Trigger bee_nest_destroyed trigger in the correct place @@ -308,15 +306,15 @@ } } } -@@ -299,6 +_,7 @@ +@@ -307,6 +_,7 @@ } else { - int count = stack.getCount(); - int damageValue = stack.getDamageValue(); -+ final ItemStack stackBeforeUse = stack.copy(); // Paper - Store stack before use for interact prediction check - InteractionResult interactionResult = stack.use(level, player, hand); - ItemStack itemStack; - if (interactionResult instanceof InteractionResult.Success success) { -@@ -321,7 +_,14 @@ + int oldCount = itemStack.getCount(); + int oldDamage = itemStack.getDamageValue(); ++ final ItemStack stackBeforeUse = itemStack.copy(); // Paper - Store stack before use for interact prediction check + InteractionResult result = itemStack.use(level, player, hand); + ItemStack resultStack; + if (result instanceof InteractionResult.Success success) { +@@ -332,7 +_,14 @@ } if (!player.isUsingItem()) { @@ -331,8 +329,8 @@ + // Paper end - Optimize sendAllDataToRemote calls } - return interactionResult; -@@ -329,15 +_,53 @@ + return result; +@@ -340,17 +_,55 @@ } } @@ -342,39 +340,41 @@ + public BlockPos interactPosition; + public InteractionHand interactHand; + public ItemStack interactItemStack; - public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) { - BlockPos blockPos = hitResult.getBlockPos(); - BlockState blockState = level.getBlockState(blockPos); + public InteractionResult useItemOn( + final ServerPlayer player, final Level level, final ItemStack itemStack, final InteractionHand hand, final BlockHitResult hitResult + ) { + BlockPos pos = hitResult.getBlockPos(); + BlockState state = level.getBlockState(pos); + boolean cancelledBlock = false; + boolean cancelledItem = false; // Paper - correctly handle items on cooldown - if (!blockState.getBlock().isEnabled(level.enabledFeatures())) { + if (!state.getBlock().isEnabled(level.enabledFeatures())) { return InteractionResult.FAIL; } else if (this.gameModeForPlayer == GameType.SPECTATOR) { - MenuProvider menuProvider = blockState.getMenuProvider(level, blockPos); + MenuProvider menuProvider = state.getMenuProvider(level, pos); - if (menuProvider != null) { - player.openMenu(menuProvider); -+ cancelledBlock = !(menuProvider instanceof MenuProvider); ++ cancelledBlock = menuProvider == null; + } + -+ if (player.getCooldowns().isOnCooldown(stack)) { ++ if (player.getCooldowns().isOnCooldown(itemStack)) { + cancelledItem = true; // Paper - correctly handle items on cooldown + } -+ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, blockPos, hitResult.getDirection(), stack, cancelledBlock, cancelledItem, hand, hitResult.getLocation()); // Paper - correctly handle items on cooldown ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, pos, hitResult.getDirection(), itemStack, cancelledBlock, cancelledItem, hand, hitResult.getLocation()); // Paper - correctly handle items on cooldown + this.firedInteract = true; + this.interactResult = event.useItemInHand() == org.bukkit.event.Event.Result.DENY; -+ this.interactPosition = blockPos.immutable(); ++ this.interactPosition = pos.immutable(); + this.interactHand = hand; -+ this.interactItemStack = stack.copy(); ++ this.interactItemStack = itemStack.copy(); + + if (event.useInteractedBlock() == org.bukkit.event.Event.Result.DENY) { + // Block acks will take care of most of it, just handle some special cases here -+ if (blockState.getBlock() instanceof net.minecraft.world.level.block.CakeBlock) { ++ if (state.getBlock() instanceof net.minecraft.world.level.block.CakeBlock) { + player.getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake -+ } else if (blockState.is(net.minecraft.world.level.block.Blocks.JIGSAW) || blockState.is(net.minecraft.world.level.block.Blocks.STRUCTURE_BLOCK) || blockState.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) { ++ } else if (state.is(net.minecraft.world.level.block.Blocks.JIGSAW) || state.is(net.minecraft.world.level.block.Blocks.STRUCTURE_BLOCK) || state.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) { + player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId)); + } + // Paper start - Fix inventory desync; SPIGOT-2867 -+ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, blockState, stack)) { ++ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, state, itemStack)) { + this.player.containerMenu.sendAllDataToRemote(); + } else { + this.player.containerMenu.forceHeldSlot(hand); @@ -383,23 +383,23 @@ + this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items + return (event.useItemInHand() != org.bukkit.event.Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS; + } else if (this.gameModeForPlayer == GameType.SPECTATOR) { -+ MenuProvider menuProvider = blockState.getMenuProvider(level, blockPos); ++ MenuProvider menuProvider = state.getMenuProvider(level, pos); + if (menuProvider != null && player.openMenu(menuProvider).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation return InteractionResult.CONSUME; } else { return InteractionResult.PASS; -@@ -362,7 +_,7 @@ +@@ -375,7 +_,7 @@ } } -- if (!stack.isEmpty() && !player.getCooldowns().isOnCooldown(stack)) { -+ if (!stack.isEmpty() && !this.interactResult) { // add !interactResult SPIGOT-764 - UseOnContext useOnContext = new UseOnContext(player, hand, hitResult); - InteractionResult interactionResult1; +- if (!itemStack.isEmpty() && !player.getCooldowns().isOnCooldown(itemStack)) { ++ if (!itemStack.isEmpty() && !this.interactResult) { // Spigot - add !this.interactResult SPIGOT-764 + UseOnContext context = new UseOnContext(player, hand, hitResult); + InteractionResult success; if (player.hasInfiniteMaterials()) { -@@ -379,6 +_,11 @@ +@@ -392,6 +_,11 @@ - return interactionResult1; + return success; } else { + // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response + if (this.interactResult && this.interactResult != cancelledItem) { diff --git a/paper-server/patches/sources/net/minecraft/server/level/Ticket.java.patch b/paper-server/patches/sources/net/minecraft/server/level/Ticket.java.patch index 8e7b25aff45b..33990c44b165 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/Ticket.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/Ticket.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/server/level/Ticket.java @@ -14,17 +_,36 @@ ExtraCodecs.NON_NEGATIVE_INT.fieldOf("level").forGetter(Ticket::getTicketLevel), - Codec.LONG.optionalFieldOf("ticks_left", 0L).forGetter(ticket -> ticket.ticksLeft) + Codec.LONG.optionalFieldOf("ticks_left", 0L).forGetter(t -> t.ticksLeft) ) -- .apply(instance, Ticket::new) -+ .apply(instance, (type, level, ticks) -> new Ticket(type, level.intValue(), ticks.longValue())) // Paper - add identifier +- .apply(i, Ticket::new) ++ .apply(i, (type, level, ticks) -> new Ticket(type, level.intValue(), ticks.longValue())) // Paper - add identifier ); private final TicketType type; private final int ticketLevel; @@ -19,7 +19,7 @@ + // Paper end - add identifier + - public Ticket(TicketType type, int ticketLevel) { + public Ticket(final TicketType type, final int ticketLevel) { - this(type, ticketLevel, type.timeout()); + // Paper start - add identifier + this(type, ticketLevel, null); @@ -29,7 +29,7 @@ + // Paper end - add identifier } - private Ticket(TicketType type, int ticketLevel, long ticksLeft) { + private Ticket(final TicketType type, final int ticketLevel, final long ticksLeft) { + // Paper start - add identifier + this(type, ticketLevel, ticksLeft, null); + } diff --git a/paper-server/patches/sources/net/minecraft/server/level/TicketType.java.patch b/paper-server/patches/sources/net/minecraft/server/level/TicketType.java.patch index 01cb41ec9b18..bc696b31915f 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/TicketType.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/TicketType.java.patch @@ -29,7 +29,7 @@ + public static final TicketType FUTURE_AWAIT = register("future_await", NO_TIMEOUT, FLAG_LOADING | FLAG_SIMULATION); // Paper + public static final TicketType CHUNK_LOAD = register("chunk_load", NO_TIMEOUT, FLAG_LOADING); // Paper - moonrise - private static TicketType register(String name, long timeout, @TicketType.Flags int flags) { + private static TicketType register(final String name, final long timeout, @TicketType.Flags final int flags) { return Registry.register(BuiltInRegistries.TICKET_TYPE, name, new TicketType(timeout, flags)); @@ -48,12 +_,20 @@ return (this.flags & FLAG_CAN_EXPIRE_IF_UNLOADED) != 0; diff --git a/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch b/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch index bf4502922504..97ed6a25d732 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/server/level/WorldGenRegion.java +++ b/net/minecraft/server/level/WorldGenRegion.java -@@ -150,6 +_,28 @@ - return chessboardDistance < this.generatingStep.directDependencies().size(); +@@ -146,6 +_,28 @@ + return distance < this.generatingStep.directDependencies().size(); } + // Paper start - if loaded util @@ -27,27 +27,17 @@ + // Paper end + @Override - public BlockState getBlockState(BlockPos pos) { + public BlockState getBlockState(final BlockPos pos) { return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos); -@@ -196,7 +_,8 @@ - if (blockState.isAir()) { - return false; - } else { -- if (dropBlock) { -+ if (dropBlock) LOGGER.warn("Potential async entity add during worldgen", new Throwable()); // Paper - Fix async entity add due to fungus trees; log when this happens -+ if (false) { // CraftBukkit - SPIGOT-6833: Do not drop during world generation - BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; - Block.dropResources(blockState, this.level, pos, blockEntity, entity, ItemStack.EMPTY); - } -@@ -239,6 +_,7 @@ +@@ -221,6 +_,7 @@ } } + private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls @Override - public boolean ensureCanWrite(BlockPos pos) { - int sectionPosX = SectionPos.blockToSectionCoord(pos.getX()); -@@ -256,6 +_,8 @@ + public boolean ensureCanWrite(final BlockPos pos) { + int chunkX = SectionPos.blockToSectionCoord(pos.getX()); +@@ -238,6 +_,8 @@ return true; } else { @@ -55,8 +45,8 @@ + if (!hasSetFarWarned) { Util.logAndPauseIfInIde( "Detected setBlock in a far chunk [" - + sectionPosX -@@ -267,6 +_,12 @@ + + chunkX +@@ -249,6 +_,12 @@ + this.generatingStep.targetStatus() + (this.currentlyGenerating == null ? "" : ", currently generating: " + this.currentlyGenerating.get()) ); @@ -69,16 +59,7 @@ return false; } } -@@ -277,7 +_,7 @@ - return false; - } else { - ChunkAccess chunk = this.getChunk(pos); -- BlockState blockState = chunk.setBlockState(pos, state, flags); -+ BlockState blockState = chunk.setBlockState(pos, state, flags); final BlockState previousBlockState = blockState; // Paper - Clear block entity before setting up a DUMMY block entity - obfhelper - if (blockState != null) { - this.level.updatePOIOnBlockStateChange(pos, blockState, state); - } -@@ -291,6 +_,17 @@ +@@ -273,6 +_,17 @@ chunk.removeBlockEntity(pos); } } else { @@ -89,24 +70,24 @@ + // Otherwise a chest block entity generated by a structure template that is later "updated" to + // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750) + // This logic is *also* found in LevelChunk#setBlockState. -+ if (previousBlockState != null && !java.util.Objects.equals(previousBlockState.getBlock(), state.getBlock())) { ++ if (oldState != null && !java.util.Objects.equals(oldState.getBlock(), blockState.getBlock())) { + chunk.removeBlockEntity(pos); + } + // Paper end - Clear block entity before setting up a DUMMY block entity - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putInt("x", pos.getX()); - compoundTag.putInt("y", pos.getY()); -@@ -316,6 +_,13 @@ + CompoundTag tag = new CompoundTag(); + tag.putInt("x", pos.getX()); + tag.putInt("y", pos.getY()); +@@ -301,6 +_,13 @@ @Override - public boolean addFreshEntity(Entity entity) { + public boolean addFreshEntity(final Entity entity) { + // CraftBukkit start + return this.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + @Override -+ public boolean addFreshEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ public boolean addFreshEntity(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { + // CraftBukkit end - int sectionPosX = SectionPos.blockToSectionCoord(entity.getBlockX()); - int sectionPosZ = SectionPos.blockToSectionCoord(entity.getBlockZ()); - this.getChunk(sectionPosX, sectionPosZ).addEntity(entity); + int xc = SectionPos.blockToSectionCoord(entity.getBlockX()); + int zc = SectionPos.blockToSectionCoord(entity.getBlockZ()); + this.getChunk(xc, zc).addEntity(entity); diff --git a/paper-server/patches/sources/net/minecraft/server/level/progress/LoggingLevelLoadListener.java.patch b/paper-server/patches/sources/net/minecraft/server/level/progress/LoggingLevelLoadListener.java.patch index f935b67dc439..25a0dfb51b9d 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/progress/LoggingLevelLoadListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/progress/LoggingLevelLoadListener.java.patch @@ -4,10 +4,10 @@ private long startTime = Long.MAX_VALUE; private long nextLogTime = Long.MAX_VALUE; -- public LoggingLevelLoadListener(boolean includePlayerChunks) { +- public LoggingLevelLoadListener(final boolean includePlayerChunks) { + // Paper start - add level + private final net.minecraft.server.level.ServerLevel level; -+ public LoggingLevelLoadListener(boolean includePlayerChunks, net.minecraft.server.level.ServerLevel level) { ++ public LoggingLevelLoadListener(final boolean includePlayerChunks, net.minecraft.server.level.ServerLevel level) { + this.level = level; + // Paper end - add level this.includePlayerChunks = includePlayerChunks; @@ -49,7 +49,7 @@ @@ -73,7 +_,7 @@ ? LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS : LevelLoadListener.Stage.LOAD_INITIAL_CHUNKS; - if (stage == stage1) { + if (stage == finalStage) { - LOGGER.info("Time elapsed: {} ms", Util.getMillis() - this.startTime); + LOGGER.info("Prepared spawn area in {} ms", Util.getMillis() - this.startTime); // Paper this.nextLogTime = Long.MAX_VALUE; diff --git a/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch b/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch index fb7e69164775..52d65de72cab 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch @@ -5,8 +5,8 @@ import net.minecraft.server.level.ClientInformation; -public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred) { -+public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @javax.annotation.Nullable String brandName, java.util.Set channels) { // Paper - public static CommonListenerCookie createInitial(GameProfile gameProfile, boolean transferred) { ++public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jspecify.annotations.Nullable String brandName, java.util.Set channels) { // Paper + public static CommonListenerCookie createInitial(final GameProfile gameProfile, final boolean transferred) { - return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred); + return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null, new java.util.HashSet<>()); // Paper } diff --git a/paper-server/patches/sources/net/minecraft/server/network/EventLoopGroupHolder.java.patch b/paper-server/patches/sources/net/minecraft/server/network/EventLoopGroupHolder.java.patch index 84488a498354..e5a97072213b 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/EventLoopGroupHolder.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/EventLoopGroupHolder.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/EventLoopGroupHolder.java +++ b/net/minecraft/server/network/EventLoopGroupHolder.java -@@ -48,11 +_,20 @@ +@@ -48,19 +_,39 @@ return LocalIoHandler.newFactory(); } }; @@ -18,32 +18,35 @@ private volatile @Nullable EventLoopGroup group; + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - use variant with address param - public static EventLoopGroupHolder remote(boolean tryNativeTransport) { - if (tryNativeTransport) { + public static EventLoopGroupHolder remote(final boolean allowNativeTransport) { ++ // Paper start - Unix domain socket support ++ return remote(null, allowNativeTransport); ++ } ++ public static EventLoopGroupHolder remote(final java.net.@Nullable SocketAddress address, final boolean allowNativeTransport) { ++ // Paper end - Unix domain socket support + if (allowNativeTransport) { if (KQueue.isAvailable()) { -@@ -66,6 +_,25 @@ + return KQUEUE; + } - return NIO; - } -+ -+ // Paper start - Unix domain socket support -+ public static EventLoopGroupHolder remote(java.net.SocketAddress address, boolean tryNativeTransport) { -+ if (tryNativeTransport) { -+ if (KQueue.isAvailable()) { -+ return KQUEUE; -+ } -+ -+ if (Epoll.isAvailable()) { + if (Epoll.isAvailable()) { +- return EPOLL; ++ // Paper start - Unix domain socket support + if (address instanceof io.netty.channel.unix.DomainSocketAddress) { + return EPOLL_UNIX_DOMAIN; + } else { + return EPOLL; + } -+ } -+ } -+ return NIO; -+ } -+ // Paper end - Unix domain socket support ++ // Paper end - Unix domain socket support + } + } + +@@ -78,7 +_,7 @@ + } + + private ThreadFactory createThreadFactory() { +- return new ThreadFactoryBuilder().setNameFormat("Netty " + this.type + " IO #%d").setDaemon(true).build(); ++ return new ThreadFactoryBuilder().setNameFormat("Netty " + this.type + " IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build(); // Paper + } - public static EventLoopGroupHolder local() { - return LOCAL; + protected abstract IoHandlerFactory ioHandlerFactory(); diff --git a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch index 821b387c4698..ab3151fb49dd 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch @@ -6,80 +6,80 @@ private final ServerInfo server; + private ByteBuf buf; // Paper - public LegacyQueryHandler(ServerInfo server) { + public LegacyQueryHandler(final ServerInfo server) { this.server = server; @@ -22,6 +_,17 @@ @Override - public void channelRead(ChannelHandlerContext ctx, Object message) { - ByteBuf byteBuf = (ByteBuf)message; + public void channelRead(final ChannelHandlerContext ctx, final Object msg) { + ByteBuf in = (ByteBuf)msg; + // Paper start - Make legacy ping handler more reliable + if (this.buf != null) { + try { -+ readLegacy1_6(ctx, byteBuf); ++ this.readLegacy1_6(ctx, in); + } finally { -+ byteBuf.release(); ++ in.release(); + } + return; + } + // Paper end - Make legacy ping handler more reliable + - byteBuf.markReaderIndex(); - boolean flag = true; + in.markReaderIndex(); + boolean connectNormally = true; @@ -33,9 +_,19 @@ - SocketAddress socketAddress = ctx.channel().remoteAddress(); - int i = byteBuf.readableBytes(); -+ String string = null; // Paper - if (i == 0) { -- LOGGER.debug("Ping: (<1.3.x) from {}", socketAddress); -- String string = createVersion0Response(this.server); -+ LOGGER.debug("Ping: (<1.3.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketAddress : ""); // Paper - Respect logIPs option + SocketAddress socket = ctx.channel().remoteAddress(); + int length = in.readableBytes(); ++ String body = null; // Paper + if (length == 0) { +- LOGGER.debug("Ping: (<1.3.x) from {}", socket); +- String body = createVersion0Response(this.server); ++ LOGGER.debug("Ping: (<1.3.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socket : ""); // Paper - Respect logIPs option + // Paper start - Call PaperServerListPingEvent and use results -+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socketAddress, 39, null); ++ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socket, 39, null); + if (event == null) { + ctx.close(); -+ byteBuf.release(); -+ flag = false; ++ in.release(); ++ connectNormally = false; + return; + } -+ string = String.format(Locale.ROOT, "%s§%d§%d", com.destroystokyo.paper.network.PaperLegacyStatusClient.getUnformattedMotd(event), event.getNumPlayers(), event.getMaxPlayers()); ++ body = String.format(Locale.ROOT, "%s§%d§%d", com.destroystokyo.paper.network.PaperLegacyStatusClient.getUnformattedMotd(event), event.getNumPlayers(), event.getMaxPlayers()); + // Paper end - Call PaperServerListPingEvent and use results - sendFlushAndClose(ctx, createLegacyDisconnectPacket(ctx.alloc(), string)); + sendFlushAndClose(ctx, createLegacyDisconnectPacket(ctx.alloc(), body)); } else { - if (byteBuf.readUnsignedByte() != 1) { + if (in.readUnsignedByte() != 1) { @@ -43,16 +_,39 @@ } - if (byteBuf.isReadable()) { -- if (!readCustomPayloadPacket(byteBuf)) { + if (in.isReadable()) { +- if (!readCustomPayloadPacket(in)) { + // Paper start - Replace below -+ if (byteBuf.readUnsignedByte() != LegacyProtocolUtils.CUSTOM_PAYLOAD_PACKET_ID) { -+ string = this.readLegacy1_6(ctx, byteBuf); -+ if (string == null) { ++ if (in.readUnsignedByte() != LegacyProtocolUtils.CUSTOM_PAYLOAD_PACKET_ID) { ++ body = this.readLegacy1_6(ctx, in); ++ if (body == null) { + return; + } + } + // Paper end - Replace below + } else { -+ LOGGER.debug("Ping: (1.4-1.5.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketAddress : ""); // Paper - Respect logIPs option ++ LOGGER.debug("Ping: (1.4-1.5.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socket : ""); // Paper - Respect logIPs option + } + + // Paper start - Call PaperServerListPingEvent and use results -+ if (string == null) { -+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socketAddress, 127, null); // Paper ++ if (body == null) { ++ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socket, 127, null); // Paper + if (event == null) { + ctx.close(); -+ byteBuf.release(); -+ flag = false; ++ in.release(); ++ connectNormally = false; return; } -- LOGGER.debug("Ping: (1.6) from {}", socketAddress); +- LOGGER.debug("Ping: (1.6) from {}", socket); - } else { -- LOGGER.debug("Ping: (1.4-1.5.x) from {}", socketAddress); +- LOGGER.debug("Ping: (1.4-1.5.x) from {}", socket); + // See createVersion1Response -+ string = String.format( ++ body = String.format( + Locale.ROOT, + "§1\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", + event.getProtocolVersion(), this.server.getServerVersion(), @@ -90,17 +90,17 @@ + // Paper end - Call PaperServerListPingEvent and use results } - -- String string = createVersion1Response(this.server); - sendFlushAndClose(ctx, createLegacyDisconnectPacket(ctx.alloc(), string)); +- String body = createVersion1Response(this.server); + sendFlushAndClose(ctx, createLegacyDisconnectPacket(ctx.alloc(), body)); } -@@ -110,6 +_,98 @@ +@@ -110,6 +_,96 @@ server.getMaxPlayers() ); } + + // Paper start -+ private static @javax.annotation.Nullable String readLegacyString(ByteBuf buf) { ++ private static @org.jspecify.annotations.Nullable String readLegacyString(final ByteBuf buf) { + int size = buf.readShort() * Character.BYTES; + if (!buf.isReadable(size)) { + return null; @@ -111,7 +111,7 @@ + return result; + } + -+ private @javax.annotation.Nullable String readLegacy1_6(ChannelHandlerContext ctx, ByteBuf part) { ++ private @org.jspecify.annotations.Nullable String readLegacy1_6(final ChannelHandlerContext ctx, final ByteBuf part) { + ByteBuf buf = this.buf; + + if (buf == null) { @@ -133,7 +133,7 @@ + } + + if (!string.equals(LegacyProtocolUtils.CUSTOM_PAYLOAD_PACKET_PING_CHANNEL)) { -+ removeHandler(ctx); ++ this.removeHandler(ctx); + return null; + } + @@ -144,13 +144,13 @@ + int protocolVersion = buf.readByte(); + String host = readLegacyString(buf); + if (host == null) { -+ removeHandler(ctx); ++ this.removeHandler(ctx); + return null; + } + + int port = buf.readInt(); + if (buf.isReadable()) { -+ removeHandler(ctx); ++ this.removeHandler(ctx); + return null; + } + @@ -161,19 +161,17 @@ + + net.minecraft.server.MinecraftServer server = net.minecraft.server.MinecraftServer.getServer(); + java.net.InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port); -+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest( -+ server, (java.net.InetSocketAddress) ctx.channel().remoteAddress(), protocolVersion, virtualHost); ++ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(server, (java.net.InetSocketAddress) ctx.channel().remoteAddress(), protocolVersion, virtualHost); + if (event == null) { + ctx.close(); + return null; + } + -+ String response = String.format("§1\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", event.getProtocolVersion(), event.getVersion(), -+ com.destroystokyo.paper.network.PaperLegacyStatusClient.getMotd(event), event.getNumPlayers(), event.getMaxPlayers()); ++ String response = String.format("§1\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", event.getProtocolVersion(), event.getVersion(), com.destroystokyo.paper.network.PaperLegacyStatusClient.getMotd(event), event.getNumPlayers(), event.getMaxPlayers()); + return response; + } + -+ private void removeHandler(ChannelHandlerContext ctx) { ++ private void removeHandler(final ChannelHandlerContext ctx) { + ByteBuf buf = this.buf; + this.buf = null; + @@ -183,7 +181,7 @@ + } + + @Override -+ public void handlerRemoved(ChannelHandlerContext ctx) { ++ public void handlerRemoved(final ChannelHandlerContext ctx) { + if (this.buf != null) { + this.buf.release(); + this.buf = null; @@ -191,5 +189,5 @@ + } + // Paper end - private static void sendFlushAndClose(ChannelHandlerContext ctx, ByteBuf buffer) { - ctx.pipeline().firstContext().writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); + private static void sendFlushAndClose(final ChannelHandlerContext ctx, final ByteBuf out) { + ctx.pipeline().firstContext().writeAndFlush(out).addListener(ChannelFutureListener.CLOSE); diff --git a/paper-server/patches/sources/net/minecraft/server/network/PlayerChunkSender.java.patch b/paper-server/patches/sources/net/minecraft/server/network/PlayerChunkSender.java.patch index 0681c61c8ac3..fcbaf082f271 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/PlayerChunkSender.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/PlayerChunkSender.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/server/network/PlayerChunkSender.java +++ b/net/minecraft/server/network/PlayerChunkSender.java @@ -44,6 +_,11 @@ - public void dropChunk(ServerPlayer player, ChunkPos chunkPos) { - if (!this.pendingChunks.remove(chunkPos.toLong()) && player.isAlive()) { - player.connection.send(new ClientboundForgetLevelChunkPacket(chunkPos)); + public void dropChunk(final ServerPlayer player, final ChunkPos pos) { + if (!this.pendingChunks.remove(pos.pack()) && player.isAlive()) { + player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); + // Paper start - PlayerChunkUnloadEvent + if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(chunkPos.longKey), player.getBukkitEntity()).callEvent(); ++ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(pos.pack()), player.getBukkitEntity()).callEvent(); + } + // Paper end - PlayerChunkUnloadEvent } @@ -14,11 +14,11 @@ @@ -75,6 +_,11 @@ - private static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) { - packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null)); + private static void sendChunk(final ServerGamePacketListenerImpl connection, final ServerLevel level, final LevelChunk chunk) { + connection.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null)); + // Paper start - PlayerChunkLoadEvent + if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent(); ++ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), connection.getPlayer().getBukkitEntity()).callEvent(); + } + // Paper end - PlayerChunkLoadEvent ChunkPos pos = chunk.getPos(); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index 0f41a4c322e1..dc4d70a76b47 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -25,7 +25,7 @@ + public final java.util.Set pluginMessagerChannels; + // Paper end - retain certain values - public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { + public ServerCommonPacketListenerImpl(final MinecraftServer server, final Connection connection, final CommonListenerCookie cookie) { this.server = server; @@ -53,7 +_,18 @@ this.keepAliveTime = Util.getMillis(); @@ -47,7 +47,7 @@ private void close() { if (!this.closed) { @@ -83,7 +_,7 @@ - this.latency = (this.latency * 3 + i) / 4; + this.latency = (this.latency * 3 + time) / 4; this.keepAlivePending = false; } else if (!this.isSingleplayerOwner()) { - this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE); @@ -56,7 +56,7 @@ } @@ -91,14 +_,88 @@ - public void handlePong(ServerboundPongPacket packet) { + public void handlePong(final ServerboundPongPacket serverboundPongPacket) { } + // Paper start @@ -65,7 +65,7 @@ + // Paper end + @Override - public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + public void handleCustomPayload(final ServerboundCustomPayloadPacket packet) { + // Paper start + if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) { + return; @@ -101,7 +101,7 @@ + + this.cserver.getMessenger().dispatchIncomingMessage(paperConnection(), identifier.toString(), data); + } catch (final Exception e) { -+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't handle custom payload on channel {}", identifier, e); ++ LOGGER.error("Couldn't handle custom payload on channel {}", identifier, e); + this.disconnect(net.minecraft.network.chat.Component.literal("Invalid custom payload payload!"), io.papermc.paper.connection.DisconnectionReason.INVALID_PAYLOAD); // Paper - kick event cause + } + } @@ -132,7 +132,7 @@ } @Override - public void handleCustomClickAction(ServerboundCustomClickActionPacket packet) { + public void handleCustomClickAction(final ServerboundCustomClickActionPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.server.packetProcessor()); this.server.handleCustomClickAction(packet.id(), packet.payload()); + // Paper start - Implement click callbacks with custom click action @@ -173,7 +173,7 @@ } @Override - public void handleCookieResponse(ServerboundCookieResponsePacket packet) { + public void handleCookieResponse(final ServerboundCookieResponsePacket packet) { - this.disconnect(DISCONNECT_UNEXPECTED_QUERY); + if (this.paperConnection().handleCookieResponse(packet)) return; // Paper + this.disconnect(DISCONNECT_UNEXPECTED_QUERY, io.papermc.paper.connection.DisconnectionReason.INVALID_COOKIE); // Paper - kick event cause @@ -181,11 +181,11 @@ protected void keepConnectionAlive() { Profiler.get().push("keepAlive"); - long millis = Util.getMillis(); -- if (!this.isSingleplayerOwner() && millis - this.keepAliveTime >= 15000L) { + long now = Util.getMillis(); +- if (!this.isSingleplayerOwner() && now - this.keepAliveTime >= 15000L) { + // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings + // This should effectively place the keepalive handling back to "as it was" before 1.12.2 -+ final long elapsedTime = millis - this.keepAliveTime; ++ final long elapsedTime = now - this.keepAliveTime; + if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets if (this.keepAlivePending) { - this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE); @@ -193,13 +193,13 @@ + this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause + } + // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings - } else if (this.checkIfClosed(millis)) { + } else if (this.checkIfClosed(now)) { this.keepAlivePending = true; - this.keepAliveTime = millis; + this.keepAliveTime = now; @@ -135,7 +_,7 @@ - private boolean checkIfClosed(long time) { + private boolean checkIfClosed(final long now) { if (this.closed) { - if (time - this.closedListenerTime >= 15000L) { + if (now - this.closedListenerTime >= 15000L) { - this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE); + this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause } @@ -208,7 +208,7 @@ @@ -158,6 +_,13 @@ } - public void send(Packet packet, @Nullable ChannelFutureListener sendListener) { + public void send(final Packet packet, final @Nullable ChannelFutureListener listener) { + // CraftBukkit start + if (packet == null || this.processedDisconnect) { // Spigot + return; @@ -219,12 +219,12 @@ if (packet.isTerminal()) { this.close(); } -@@ -174,19 +_,114 @@ +@@ -174,15 +_,111 @@ } } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - kick event causes - public void disconnect(Component reason) { + public void disconnect(final Component reason) { - this.disconnect(new DisconnectionDetails(reason)); + // Paper start - kick event causes + this.disconnect(reason, io.papermc.paper.connection.DisconnectionReason.UNKNOWN); @@ -235,11 +235,7 @@ + // Paper end - kick event causes } - public void disconnect(DisconnectionDetails disconnectionDetails) { -- this.connection -- .send( -- new ClientboundDisconnectPacket(disconnectionDetails.reason()), -- PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails)) + public void disconnect(final DisconnectionDetails details) { + // CraftBukkit start - fire PlayerKickEvent + if (this.processedDisconnect) { + return; @@ -248,7 +244,7 @@ + org.bukkit.craftbukkit.util.Waitable waitable = new org.bukkit.craftbukkit.util.Waitable() { + @Override + protected Object evaluate() { -+ ServerCommonPacketListenerImpl.this.disconnect(disconnectionDetails); ++ ServerCommonPacketListenerImpl.this.disconnect(details); + return null; + } + }; @@ -271,13 +267,13 @@ + net.kyori.adventure.text.Component rawLeaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? serverGamePacketListener.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(serverGamePacketListener.player.getScoreboardName())); // Paper - Adventure + + net.minecraft.server.level.ServerPlayer player = serverGamePacketListener.player; -+ org.bukkit.event.player.PlayerKickEvent.Cause cause = disconnectionDetails.disconnectionReason().orElseThrow().game().orElse(org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); ++ org.bukkit.event.player.PlayerKickEvent.Cause cause = details.disconnectionReason().orElseThrow().game().orElse(org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); + org.bukkit.event.player.PlayerKickEvent event = new org.bukkit.event.player.PlayerKickEvent( + player.getBukkitEntity(), -+ io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionDetails.reason()), ++ io.papermc.paper.adventure.PaperAdventure.asAdventure(details.reason()), + rawLeaveMessage, cause + - ); ++ ); + + if (this.cserver.getServer().isRunning()) { + this.cserver.getPluginManager().callEvent(event); @@ -298,21 +294,18 @@ + } + } else { + // TODO: Add event for config event -+ reason = disconnectionDetails.reason(); ++ reason = details.reason(); + leaveMessage = null; + } + + // Send the possibly modified leave message -+ this.disconnect0(new DisconnectionDetails(reason, disconnectionDetails.report(), disconnectionDetails.bugReportLink(), java.util.Optional.ofNullable(leaveMessage), disconnectionDetails.disconnectionReason())); ++ this.disconnect0(new DisconnectionDetails(reason, details.report(), details.bugReportLink(), java.util.Optional.ofNullable(leaveMessage), details.disconnectionReason())); + } + -+ private void disconnect0(DisconnectionDetails disconnectionDetails) { -+ this.connection -+ .send( -+ new ClientboundDisconnectPacket(disconnectionDetails.reason()), -+ PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails)) -+ ); -+ this.onDisconnect(disconnectionDetails); ++ private void disconnect0(final DisconnectionDetails details) { ++ // CraftBukkit end + this.connection.send(new ClientboundDisconnectPacket(details.reason()), PacketSendListener.thenRun(() -> this.connection.disconnect(details))); ++ this.onDisconnect(details); // CraftBukkit - fire quit instantly this.connection.setReadOnly(); - this.server.executeBlocking(this.connection::handleDisconnection); - } @@ -341,10 +334,10 @@ protected boolean isSingleplayerOwner() { return this.server.isSingleplayerOwner(new NameAndId(this.playerProfile())); -@@ -204,6 +_,6 @@ +@@ -200,6 +_,6 @@ } - protected CommonListenerCookie createCookie(ClientInformation clientInformation) { + protected CommonListenerCookie createCookie(final ClientInformation clientInformation) { - return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred); + return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels); // Paper } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 4f05492b68cd..9d6515de84a2 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -6,7 +6,7 @@ private @Nullable PrepareSpawnTask prepareSpawnTask; + public io.papermc.paper.connection.PaperPlayerConfigurationConnection paperConnection; // Paper - public ServerConfigurationPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { + public ServerConfigurationPacketListenerImpl(final MinecraftServer server, final Connection connection, final CommonListenerCookie cookie) { super(server, connection, cookie); this.gameProfile = cookie.gameProfile(); this.clientInformation = cookie.clientInformation(); @@ -31,7 +31,7 @@ @@ -66,6 +_,11 @@ @Override - public void onDisconnect(DisconnectionDetails details) { + public void onDisconnect(final DisconnectionDetails details) { + // Paper start - Debugging + if (this.server.isDebugging()) { + ServerConfigurationPacketListenerImpl.LOGGER.info("{} ({}) lost connection: {}, while in configuration phase {}", this.gameProfile.name(), this.gameProfile.id(), details.reason().getString(), this.currentTask != null ? this.currentTask.type().id() : "null"); @@ -56,9 +56,9 @@ + // Paper end } - LayeredRegistryAccess layeredRegistryAccess = this.server.registries(); + LayeredRegistryAccess registries = this.server.registries(); @@ -97,11 +_,12 @@ - this.synchronizeRegistriesTask = new SynchronizeRegistriesTask(list, layeredRegistryAccess); + this.synchronizeRegistriesTask = new SynchronizeRegistriesTask(knownPacks, registries); this.configurationTasks.add(this.synchronizeRegistriesTask); this.addOptionalTasks(); + this.configurationTasks.add(new io.papermc.paper.connection.PaperConfigurationTask(this)); // Paper @@ -71,15 +71,15 @@ this.configurationTasks.add(this.prepareSpawnTask); this.configurationTasks.add(new JoinWorldTask()); this.startNextTask(); -@@ -132,12 +_,14 @@ +@@ -130,12 +_,14 @@ @Override - public void handleClientInformation(ServerboundClientInformationPacket packet) { + public void handleClientInformation(final ServerboundClientInformationPacket packet) { this.clientInformation = packet.information(); + this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper } @Override - public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { + public void handleResourcePackResponse(final ServerboundResourcePackPacket packet) { super.handleResourcePackResponse(packet); - if (packet.action().isTerminal()) { + this.connection.resourcePackStatus = org.bukkit.event.player.PlayerResourcePackStatusEvent.Status.values()[packet.action().ordinal()]; // Paper @@ -87,16 +87,16 @@ this.finishCurrentTask(ServerResourcePackConfigurationTask.TYPE); } } -@@ -171,7 +_,7 @@ +@@ -169,7 +_,7 @@ return; } -- Component component = playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(this.gameProfile)); -+ Component component = org.bukkit.craftbukkit.event.CraftEventFactory.handleLoginResult(playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(this.gameProfile)), this.paperConnection, this.connection, this.gameProfile, this.server, false); // Paper - Login event logic - if (component != null) { - this.disconnect(component); +- Component loginError = playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(this.gameProfile)); ++ Component loginError = org.bukkit.craftbukkit.event.CraftEventFactory.handleLoginResult(playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(this.gameProfile)), this.paperConnection, this.connection, this.gameProfile, this.server, false); // Paper - Login event logic + if (loginError != null) { + this.disconnect(loginError); return; -@@ -231,4 +_,29 @@ +@@ -229,4 +_,29 @@ this.startNextTask(); } } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch index d4308c9813fd..78ca3bd5318c 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -48,9 +_,31 @@ +@@ -49,9 +_,31 @@ this.running = true; } @@ -15,7 +15,7 @@ + } + // Paper end - prevent blocking on adding a new connection while the server is ticking + - public void startTcpServerListener(@Nullable InetAddress address, int port) throws IOException { + public void startTcpServerListener(final @Nullable InetAddress address, final int port) throws IOException { + // Paper start - Unix domain socket support + this.startTcpServerListener(new java.net.InetSocketAddress(address, port)); + } @@ -33,7 +33,7 @@ this.channels .add( new ServerBootstrap() -@@ -74,22 +_,64 @@ +@@ -79,22 +_,64 @@ Connection connection = (Connection)(rateLimitPacketsPerSecond > 0 ? new RateKickingConnection(rateLimitPacketsPerSecond) : new Connection(PacketFlow.SERVERBOUND)); @@ -69,7 +69,7 @@ + // Paper end - Add support for proxy protocol + // ServerConnectionListener.this.connections.add(connection); // Paper - prevent blocking on adding a new connection while the server is ticking + ServerConnectionListener.this.pending.add(connection); // Paper - prevent blocking on adding a new connection while the server is ticking - connection.configurePacketHandler(channelPipeline); + connection.configurePacketHandler(pipeline); connection.setListenerForServerboundHandshake( new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, connection) ); @@ -98,9 +98,9 @@ + // CraftBukkit end + public SocketAddress startMemoryChannel() { - ChannelFuture channelFuture; + ChannelFuture newChannel; synchronized (this.channels) { -@@ -141,6 +_,13 @@ +@@ -150,6 +_,13 @@ public void tick() { synchronized (this.connections) { @@ -114,11 +114,11 @@ Iterator iterator = this.connections.iterator(); while (iterator.hasNext()) { -@@ -160,6 +_,7 @@ +@@ -169,6 +_,7 @@ connection.setReadOnly(); } } else { -+ if (connection.preparing) continue; // Spigot - Fix a race condition where a NetworkManager could be unregistered just before connection ++ if (connection.preparing) continue; // Spigot - Fix a race condition where a Connection could be unregistered just before connection iterator.remove(); connection.handleDisconnection(); } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index cb5a872dad48..2c97ad84b8b7 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -214,6 +_,38 @@ +@@ -222,6 +_,38 @@ import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -38,8 +38,8 @@ + public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - implements GameProtocols.Context, -@@ -234,7 +_,9 @@ + implements ServerGamePacketListener, +@@ -242,7 +_,9 @@ private int tickCount; private int ackBlockChangesUpTo = -1; private final TickThrottler chatSpamThrottler = new TickThrottler(20, 200); @@ -49,7 +49,7 @@ private double firstGoodX; private double firstGoodY; private double firstGoodZ; -@@ -258,7 +_,23 @@ +@@ -266,7 +_,23 @@ private int receivedMovePacketCount; private int knownMovePacketCount; private boolean receivedMovementThisTick; @@ -73,7 +73,7 @@ private SignedMessageChain.Decoder signedMessageDecoder; private final LastSeenMessagesValidator lastSeenMessages = new LastSeenMessagesValidator(20); private int nextChatIndex; -@@ -267,6 +_,9 @@ +@@ -275,6 +_,9 @@ private boolean waitingForSwitchToConfig; private boolean waitingForRespawn; private int clientLoadedTimeoutTimer; @@ -81,9 +81,9 @@ + private final io.papermc.paper.event.packet.ClientTickEndEvent tickEndEvent; // Paper - add client tick end event + public final io.papermc.paper.connection.PaperPlayerGameConnection playerGameConnection; // Paper - public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) { + public ServerGamePacketListenerImpl(final MinecraftServer server, final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) { super(server, connection, cookie); -@@ -276,11 +_,26 @@ +@@ -284,11 +_,26 @@ player.connection = this; player.getTextFilter().join(); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile); @@ -112,7 +112,7 @@ if (this.ackBlockChangesUpTo > -1) { this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); this.ackBlockChangesUpTo = -1; -@@ -290,11 +_,13 @@ +@@ -298,11 +_,13 @@ this.keepConnectionAlive(); this.chatSpamThrottler.tick(); this.dropSpamThrottler.tick(); @@ -127,7 +127,7 @@ } } } -@@ -310,8 +_,8 @@ +@@ -318,8 +_,8 @@ this.knownMovePacketCount = this.receivedMovePacketCount; if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) { if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) { @@ -138,7 +138,7 @@ return true; } } else { -@@ -329,8 +_,8 @@ +@@ -337,8 +_,8 @@ this.vehicleLastGoodZ = this.lastVehicle.getZ(); if (this.clientVehicleIsFloating && this.lastVehicle.getControllingPassenger() == this.player) { if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle)) { @@ -149,7 +149,7 @@ return true; } } else { -@@ -343,6 +_,12 @@ +@@ -351,6 +_,12 @@ this.aboveGroundVehicleTickCount = 0; } @@ -162,9 +162,9 @@ return false; } -@@ -408,11 +_,37 @@ +@@ -416,11 +_,37 @@ @Override - public void handlePlayerInput(ServerboundPlayerInputPacket packet) { + public void handlePlayerInput(final ServerboundPlayerInputPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + // CraftBukkit start + if (!packet.input().equals(this.player.getLastClientInput())) { @@ -201,22 +201,22 @@ + } - private static boolean containsInvalidValues(double x, double y, double z, float yRot, float xRot) { -@@ -431,17 +_,29 @@ - public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { + private static boolean containsInvalidValues(final double x, final double y, final double z, final float yRot, final float xRot) { +@@ -439,11 +_,23 @@ + public void handleMoveVehicle(final ServerboundMoveVehiclePacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (containsInvalidValues(packet.position().x(), packet.position().y(), packet.position().z(), packet.yRot(), packet.xRot())) { - this.disconnect(Component.translatable("multiplayer.disconnect.invalid_vehicle_movement")); + this.disconnect(Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause } else if (!this.updateAwaitingTeleport() && this.hasClientLoaded()) { - Entity rootVehicle = this.player.getRootVehicle(); + Entity vehicle = this.player.getRootVehicle(); + // Paper start - Don't allow vehicle movement from players while teleporting -+ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || rootVehicle.isRemoved()) { ++ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || vehicle.isRemoved()) { + return; + } + // Paper end - Don't allow vehicle movement from players while teleporting - if (rootVehicle != this.player && rootVehicle.getControllingPassenger() == this.player && rootVehicle == this.lastVehicle) { - ServerLevel serverLevel = this.player.level(); + if (vehicle != this.player && vehicle.getControllingPassenger() == this.player && vehicle == this.lastVehicle) { + ServerLevel level = this.player.level(); + // CraftBukkit - store current player position + double prevX = this.player.getX(); + double prevY = this.player.getY(); @@ -224,32 +224,23 @@ + float prevYaw = this.player.getYRot(); + float prevPitch = this.player.getXRot(); + // CraftBukkit end - double x = rootVehicle.getX(); - double y = rootVehicle.getY(); - double z = rootVehicle.getZ(); -- double d = clampHorizontal(packet.position().x()); -- double d1 = clampVertical(packet.position().y()); -- double d2 = clampHorizontal(packet.position().z()); -+ double d = clampHorizontal(packet.position().x()); final double toX = d; // Paper - OBFHELPER -+ double d1 = clampVertical(packet.position().y()); final double toY = d1; // Paper - OBFHELPER -+ double d2 = clampHorizontal(packet.position().z()); final double toZ = d2; // Paper - OBFHELPER - float f = Mth.wrapDegrees(packet.yRot()); - float f1 = Mth.wrapDegrees(packet.xRot()); - double d3 = d - this.vehicleFirstGoodX; -@@ -449,16 +_,61 @@ - double d5 = d2 - this.vehicleFirstGoodZ; - double d6 = rootVehicle.getDeltaMovement().lengthSqr(); - double d7 = d3 * d3 + d4 * d4 + d5 * d5; -- if (d7 - d6 > 100.0 && !this.isSingleplayerOwner()) { + double oldX = vehicle.getX(); + double oldY = vehicle.getY(); + double oldZ = vehicle.getZ(); +@@ -457,7 +_,52 @@ + double zDist = targetZ - this.vehicleFirstGoodZ; + double expectedDist = vehicle.getDeltaMovement().lengthSqr(); + double movedDist = xDist * xDist + yDist * yDist + zDist * zDist; +- if (movedDist - expectedDist > 100.0 && !this.isSingleplayerOwner()) { + // Paper start - fix large move vectors killing the server -+ double currDeltaX = toX - x; -+ double currDeltaY = toY - y; -+ double currDeltaZ = toZ - z; -+ d7 = Math.max(d7, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); -+ double otherFieldX = toX - this.vehicleLastGoodX; -+ double otherFieldY = toY - this.vehicleLastGoodY; -+ double otherFieldZ = toZ - this.vehicleLastGoodZ; -+ d7 = Math.max(d7, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); ++ double currDeltaX = targetX - oldX; ++ double currDeltaY = targetY - oldY; ++ double currDeltaZ = targetZ - oldZ; ++ movedDist = Math.max(movedDist, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); ++ double otherFieldX = targetX - this.vehicleLastGoodX; ++ double otherFieldY = targetY - this.vehicleLastGoodY; ++ double otherFieldZ = targetZ - this.vehicleLastGoodZ; ++ movedDist = Math.max(movedDist, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); + // Paper end - fix large move vectors killing the server + + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; @@ -263,7 +254,7 @@ + i = 1; + } + -+ if (d7 > 0) { ++ if (movedDist > 0) { + this.allowedPlayerTicks -= 1; + } else { + this.allowedPlayerTicks = 20; @@ -278,45 +269,46 @@ + + // Paper start - Prevent moving into unloaded chunks + if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && ( -+ !serverLevel.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position()))) || -+ !serverLevel.areChunksLoadedForMove(rootVehicle.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(rootVehicle.position()))) ++ !level.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(targetX, targetY, targetZ).subtract(this.player.position()))) || ++ !level.areChunksLoadedForMove(vehicle.getBoundingBox().expandTowards(new Vec3(targetX, targetY, targetZ).subtract(vehicle.position()))) + )) { -+ this.connection.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); ++ this.connection.send(ClientboundMoveVehiclePacket.fromEntity(vehicle)); + return; + } + // Paper end - Prevent moving into unloaded chunks -+ if (d7 - d6 > Math.max(100.0, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed)) && !this.isSingleplayerOwner()) { ++ if (movedDist - expectedDist > Math.max(100.0, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed)) && !this.isSingleplayerOwner()) { + // CraftBukkit end - LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", rootVehicle.getPlainTextName(), this.player.getPlainTextName(), d3, d4, d5); - this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); - return; + LOGGER.warn( + "{} (vehicle of {}) moved too quickly! {},{},{}", vehicle.getPlainTextName(), this.player.getPlainTextName(), xDist, yDist, zDist + ); +@@ -466,9 +_,9 @@ } - AABB boundingBox = rootVehicle.getBoundingBox(); -- d3 = d - this.vehicleLastGoodX; -- d4 = d1 - this.vehicleLastGoodY; -- d5 = d2 - this.vehicleLastGoodZ; -+ d3 = d - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above -+ d4 = d1 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above -+ d5 = d2 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above - boolean flag = rootVehicle.verticalCollisionBelow; - if (rootVehicle instanceof LivingEntity livingEntity && livingEntity.onClimbable()) { - livingEntity.resetFallDistance(); -@@ -475,7 +_,7 @@ - d5 = d2 - rootVehicle.getZ(); - d7 = d3 * d3 + d4 * d4 + d5 * d5; - boolean flag1 = false; -- if (d7 > 0.0625) { -+ if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot - flag1 = true; - LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getPlainTextName(), this.player.getPlainTextName(), Math.sqrt(d7)); + AABB oldAABB = vehicle.getBoundingBox(); +- xDist = targetX - this.vehicleLastGoodX; +- yDist = targetY - this.vehicleLastGoodY; +- zDist = targetZ - this.vehicleLastGoodZ; ++ xDist = targetX - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above ++ yDist = targetY - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above ++ zDist = targetZ - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above + boolean vehicleRestsOnSomething = vehicle.verticalCollisionBelow; + if (vehicle instanceof LivingEntity livingVehicle && livingVehicle.onClimbable()) { + livingVehicle.resetFallDistance(); +@@ -485,7 +_,7 @@ + zDist = targetZ - vehicle.getZ(); + movedDist = xDist * xDist + yDist * yDist + zDist * zDist; + boolean fail = false; +- if (movedDist > 0.0625) { ++ if (movedDist > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot + fail = true; + LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", vehicle.getPlainTextName(), this.player.getPlainTextName(), Math.sqrt(movedDist)); } -@@ -489,6 +_,57 @@ +@@ -498,6 +_,57 @@ } - rootVehicle.absSnapTo(d, d1, d2, f, f1); + vehicle.absSnapTo(targetX, targetY, targetZ, targetYRot, targetXRot); + // CraftBukkit start - fire PlayerMoveEvent TODO: this should be removed. -+ this.player.absSnapTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // Paper - TODO: This breaks alot of stuff ++ this.player.absSnapTo(targetX, targetY, targetZ, this.player.getYRot(), this.player.getXRot()); // Paper - TODO: This breaks alot of stuff + org.bukkit.entity.Player player = this.getCraftPlayer(); + if (!this.hasMoved) { + this.lastPosX = prevX; @@ -367,9 +359,9 @@ + } + // CraftBukkit end this.player.level().getChunkSource().move(this.player); - Vec3 vec3 = new Vec3(rootVehicle.getX() - x, rootVehicle.getY() - y, rootVehicle.getZ() - z); - this.handlePlayerKnownMovement(vec3); -@@ -519,7 +_,7 @@ + Vec3 clientDeltaMovement = new Vec3(vehicle.getX() - oldX, vehicle.getY() - oldY, vehicle.getZ() - oldZ); + this.handlePlayerKnownMovement(clientDeltaMovement); +@@ -528,7 +_,7 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (packet.getId() == this.awaitingTeleport) { if (this.awaitingPositionFromClient == null) { @@ -378,7 +370,7 @@ return; } -@@ -536,13 +_,14 @@ +@@ -545,13 +_,14 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); this.awaitingPositionFromClient = null; @@ -387,22 +379,22 @@ } @Override - public void handleAcceptPlayerLoad(ServerboundPlayerLoadedPacket packet) { + public void handleAcceptPlayerLoad(final ServerboundPlayerLoadedPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - this.markClientLoaded(); + this.markClientLoaded(false); // Paper - Add PlayerLoadedWorldEvent } @Override -@@ -563,6 +_,7 @@ +@@ -572,6 +_,7 @@ @Override - public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { + public void handleRecipeBookChangeSettingsPacket(final ServerboundRecipeBookChangeSettingsPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + CraftEventFactory.callRecipeBookSettingsEvent(this.player, packet.getBookType(), packet.isOpen(), packet.isFiltering()); // CraftBukkit this.player.getRecipeBook().setBookSetting(packet.getBookType(), packet.isOpen(), packet.isFiltering()); } -@@ -578,25 +_,110 @@ +@@ -587,25 +_,112 @@ } } @@ -412,7 +404,7 @@ + // Paper end - AsyncTabCompleteEvent + @Override - public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { + public void handleCustomCommandSuggestions(final ServerboundCommandSuggestionPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); // Paper - AsyncTabCompleteEvent; run this async + // CraftBukkit start @@ -439,9 +431,9 @@ + + private void handleCustomCommandSuggestions0(final ServerboundCommandSuggestionPacket packet) { + // Paper end - AsyncTabCompleteEvent - StringReader stringReader = new StringReader(packet.getCommand()); - if (stringReader.canRead() && stringReader.peek() == '/') { - stringReader.skip(); + StringReader command = new StringReader(packet.getCommand()); + if (command.canRead() && command.peek() == '/') { + command.skip(); } + // Paper start - AsyncTabCompleteEvent @@ -455,9 +447,9 @@ + } + + // This needs to be on main -+ this.server.scheduleOnMain(() -> this.sendServerSuggestions(packet, stringReader)); ++ this.server.scheduleOnMain(() -> this.sendServerSuggestions(packet, command)); + } else if (!completions.isEmpty()) { -+ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringReader.getTotalLength()); ++ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), command.getTotalLength()); + final com.mojang.brigadier.suggestion.SuggestionsBuilder builder = builder0.createOffset(builder0.getInput().lastIndexOf(' ') + 1); + for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) { + final Integer intSuggestion = com.google.common.primitives.Ints.tryParse(completion.suggestion()); @@ -483,90 +475,85 @@ + } + // Paper end - brig API + -+ private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader stringReader) { ++ private void sendServerSuggestions(final ServerboundCommandSuggestionPacket packet, final StringReader command) { + // Paper end - AsyncTabCompleteEvent - ParseResults parseResults = this.server.getCommands().getDispatcher().parse(stringReader, this.player.createCommandSourceStack()); + ParseResults parse = this.server.getCommands().getDispatcher().parse(command, this.player.createCommandSourceStack()); + // Paper start - Handle non-recoverable exceptions -+ if (!parseResults.getExceptions().isEmpty() -+ && parseResults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { ++ if (!parse.getExceptions().isEmpty() ++ && parse.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) { + this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); + return; + } + // Paper end - Handle non-recoverable exceptions - this.server - .getCommands() - .getDispatcher() - .getCompletionSuggestions(parseResults) - .thenAccept( - suggestions -> { -- Suggestions suggestions1 = suggestions.getList().size() <= 1000 -- ? suggestions -- : new Suggestions(suggestions.getRange(), suggestions.getList().subList(0, 1000)); -- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions1)); -+ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false -+ if (!org.spigotmc.SpigotConfig.sendNamespaced && suggestions.getRange().getStart() <= 1) { -+ suggestions.getList().removeIf(suggestion -> suggestion.getText().contains(":")); -+ } -+ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false -+ // Paper start - Brigadier API -+ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); -+ suggestEvent.setCancelled(suggestions.isEmpty()); -+ if (suggestEvent.callEvent()) { -+ this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), limitTo(suggestEvent.getSuggestions(), ServerGamePacketListenerImpl.MAX_COMMAND_SUGGESTIONS))); -+ } -+ // Paper end - Brigadier API - } - ); + this.server.getCommands().getDispatcher().getCompletionSuggestions(parse).thenAccept(results -> { +- Suggestions suggestions = results.getList().size() <= 1000 ? results : new Suggestions(results.getRange(), results.getList().subList(0, 1000)); +- this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); ++ // Paper start - Don't tab-complete namespaced commands if send-namespaced is false ++ if (!org.spigotmc.SpigotConfig.sendNamespaced && results.getRange().getStart() <= 1) { ++ results.getList().removeIf(suggestion -> suggestion.getText().contains(":")); ++ } ++ // Paper end - Don't tab-complete namespaced commands if send-namespaced is false ++ // Paper start - Brigadier API ++ com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), results, packet.getCommand()); ++ suggestEvent.setCancelled(results.isEmpty()); ++ if (suggestEvent.callEvent()) { ++ this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), limitTo(suggestEvent.getSuggestions(), ServerGamePacketListenerImpl.MAX_COMMAND_SUGGESTIONS))); ++ } ++ // Paper end - Brigadier API + }); } -@@ -604,7 +_,7 @@ + @Override - public void handleSetCommandBlock(ServerboundSetCommandBlockPacket packet) { + public void handleSetCommandBlock(final ServerboundSetCommandBlockPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - if (!this.player.canUseGameMasterBlocks()) { + if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); } else { - BaseCommandBlock baseCommandBlock = null; -@@ -665,7 +_,7 @@ + BaseCommandBlock commandBlock = null; +@@ -666,7 +_,7 @@ @Override - public void handleSetCommandMinecart(ServerboundSetCommandMinecartPacket packet) { + public void handleSetCommandMinecart(final ServerboundSetCommandMinecartPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - if (!this.player.canUseGameMasterBlocks()) { + if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); } else { BaseCommandBlock commandBlock = packet.getCommandBlock(this.player.level()); -@@ -703,11 +_,11 @@ - boolean flag = this.player.hasInfiniteMaterials() && packet.includeData(); - ItemStack cloneItemStack = blockState.getCloneItemStack(serverLevel, blockPos, flag); - if (!cloneItemStack.isEmpty()) { -- if (flag) { -+ if (flag && this.player.getBukkitEntity().hasPermission("minecraft.nbt.copy")) { // Spigot - addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack); +@@ -702,11 +_,11 @@ + boolean includeData = this.player.hasInfiniteMaterials() && packet.includeData(); + ItemStack itemStack = blockState.getCloneItemStack(level, pos, includeData); + if (!itemStack.isEmpty()) { +- if (includeData) { ++ if (includeData && this.player.getBukkitEntity().hasPermission("minecraft.nbt.copy")) { // Spigot + addBlockDataToItem(blockState, level, pos, itemStack); } -- this.tryPickItem(cloneItemStack); -+ this.tryPickItem(cloneItemStack, blockPos, null, packet.includeData()); // Paper - Extend PlayerPickItemEvent API +- this.tryPickItem(itemStack); ++ this.tryPickItem(itemStack, pos, null, packet.includeData()); // Paper - Extend PlayerPickItemEvent API } } } -@@ -734,27 +_,40 @@ - if (entityOrPart != null && this.player.isWithinEntityInteractionRange(entityOrPart, 3.0)) { - ItemStack pickResult = entityOrPart.getPickResult(); - if (pickResult != null && !pickResult.isEmpty()) { -- this.tryPickItem(pickResult); -+ this.tryPickItem(pickResult, null, entityOrPart, packet.includeData()); // Paper - Extend PlayerPickItemEvent API +@@ -733,7 +_,7 @@ + if (entity != null && this.player.isWithinEntityInteractionRange(entity, 3.0)) { + ItemStack itemStack = entity.getPickResult(); + if (itemStack != null && !itemStack.isEmpty()) { +- this.tryPickItem(itemStack); ++ this.tryPickItem(itemStack, null, entity, packet.includeData()); // Paper - Extend PlayerPickItemEvent API } + + if (packet.includeData() && this.player.canUseGameMasterBlocks() && entity instanceof Avatar avatar) { +@@ -742,22 +_,35 @@ } } -- private void tryPickItem(ItemStack stack) { -+ private void tryPickItem(ItemStack stack, @Nullable BlockPos blockPos, @Nullable Entity entity, boolean includeData) { // Paper - Extend PlayerPickItemEvent API - if (stack.isItemEnabled(this.player.level().enabledFeatures())) { +- private void tryPickItem(final ItemStack itemStack) { ++ private void tryPickItem(ItemStack itemStack, @Nullable BlockPos blockPos, @Nullable Entity entity, boolean includeData) { // Paper - Extend PlayerPickItemEvent API + if (itemStack.isItemEnabled(this.player.level().enabledFeatures())) { Inventory inventory = this.player.getInventory(); - int i = inventory.findSlotMatchingItem(stack); + int slotWithExistingItem = inventory.findSlotMatchingItem(itemStack); + // Paper start - Add PlayerPickItemEvent -+ final int sourceSlot = i; ++ final int sourceSlot = slotWithExistingItem; + final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot(); + final org.bukkit.entity.Player bukkitPlayer = this.player.getBukkitEntity(); + final io.papermc.paper.event.player.PlayerPickItemEvent event = entity != null @@ -575,20 +562,20 @@ + if (!event.callEvent()) { + return; + } -+ i = event.getSourceSlot(); ++ slotWithExistingItem = event.getSourceSlot(); + // Paper end - Add PlayerPickItemEvent - if (i != -1) { -- if (Inventory.isHotbarSlot(i)) { -- inventory.setSelectedSlot(i); -+ if (Inventory.isHotbarSlot(i) && Inventory.isHotbarSlot(event.getTargetSlot())) { // Paper - Add PlayerPickItemEvent + if (slotWithExistingItem != -1) { +- if (Inventory.isHotbarSlot(slotWithExistingItem)) { +- inventory.setSelectedSlot(slotWithExistingItem); ++ if (Inventory.isHotbarSlot(slotWithExistingItem) && Inventory.isHotbarSlot(event.getTargetSlot())) { // Paper - Add PlayerPickItemEvent + inventory.setSelectedSlot(event.getTargetSlot()); // Paper - Add PlayerPickItemEvent } else { -- inventory.pickSlot(i); -+ inventory.pickSlot(i, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent +- inventory.pickSlot(slotWithExistingItem); ++ inventory.pickSlot(slotWithExistingItem, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent } } else if (this.player.hasInfiniteMaterials()) { -- inventory.addAndPickItem(stack); -+ inventory.addAndPickItem(stack, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent +- inventory.addAndPickItem(itemStack); ++ inventory.addAndPickItem(itemStack, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent } this.send(new ClientboundSetHeldSlotPacket(inventory.getSelectedSlot())); @@ -597,24 +584,42 @@ } } -@@ -932,6 +_,13 @@ +@@ -790,7 +_,7 @@ + @Override + public void handleSetGameRule(final ServerboundSetGameRulePacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); +- if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER)) { ++ if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER) && !this.player.getBukkitEntity().hasPermission("minecraft.command.gamerule")) { // Paper - add permission check + LOGGER.warn("Player {} tried to set game rule values without required permissions", this.player.getGameProfile().name()); + } else { + GameRules gameRules = this.player.level().getGameRules(); +@@ -808,7 +_,7 @@ + + private void setGameRuleValue(final GameRules gameRules, final GameRule rule, final String value) { + rule.deserialize(value).result().ifPresent(parsedValue -> { +- gameRules.set(rule, (T)parsedValue, this.server); ++ parsedValue = org.bukkit.craftbukkit.event.CraftEventFactory.handleGameRuleSet(rule, parsedValue, this.player.level(), this.player.getBukkitEntity()).value(); // Paper - per-world game rules and event + this.broadcastGameRuleChangeToOperators(rule, (T)parsedValue); + }); + } +@@ -967,6 +_,13 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - int item = packet.getItem(); - if (this.player.containerMenu instanceof MerchantMenu merchantMenu) { + int selection = packet.getItem(); + if (this.player.containerMenu instanceof MerchantMenu menu) { + // CraftBukkit start -+ final org.bukkit.event.inventory.TradeSelectEvent tradeSelectEvent = CraftEventFactory.callTradeSelectEvent(item, merchantMenu); ++ final org.bukkit.event.inventory.TradeSelectEvent tradeSelectEvent = CraftEventFactory.callTradeSelectEvent(selection, menu); + if (tradeSelectEvent.isCancelled()) { + this.player.containerMenu.sendAllDataToRemote(); + return; + } + // CraftBukkit end - if (!merchantMenu.stillValid(this.player)) { - LOGGER.debug("Player {} interacted with invalid menu {}", this.player, merchantMenu); + if (!menu.stillValid(this.player)) { + LOGGER.debug("Player {} interacted with invalid menu {}", this.player, menu); return; -@@ -944,6 +_,51 @@ +@@ -979,6 +_,51 @@ @Override - public void handleEditBook(ServerboundEditBookPacket packet) { + public void handleEditBook(final ServerboundEditBookPacket packet) { + // Paper start - Book size limits + final io.papermc.paper.configuration.type.number.IntOr.Disabled pageMax = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax; + if (!this.cserver.isPrimaryThread() && pageMax.enabled()) { @@ -662,63 +667,49 @@ + // CraftBukkit end int slot = packet.slot(); if (Inventory.isHotbarSlot(slot) || slot == 40) { - List list = Lists.newArrayList(); -@@ -958,10 +_,14 @@ + List contents = Lists.newArrayList(); +@@ -993,10 +_,14 @@ } - private void updateBookContents(List pages, int index) { -- ItemStack item = this.player.getInventory().getItem(index); + private void updateBookContents(final List contents, final int slot) { +- ItemStack carried = this.player.getInventory().getItem(slot); + // CraftBukkit start -+ ItemStack handItem = this.player.getInventory().getItem(index); -+ ItemStack item = handItem.copy(); ++ ItemStack handItem = this.player.getInventory().getItem(slot); ++ ItemStack carried = handItem.copy(); + // CraftBukkit end - if (item.has(DataComponents.WRITABLE_BOOK_CONTENT)) { - List> list = pages.stream().map(this::filterableFromOutgoing).toList(); - item.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list)); -+ this.player.getInventory().setItem(index, CraftEventFactory.handleEditBookEvent(this.player, index, handItem, item)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) + if (carried.has(DataComponents.WRITABLE_BOOK_CONTENT)) { + List> pages = contents.stream().map(this::filterableFromOutgoing).toList(); + carried.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(pages)); ++ this.player.getInventory().setItem(slot, CraftEventFactory.handleEditBookEvent(this.player, slot, handItem, carried)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) } } -@@ -974,7 +_,8 @@ - itemStack.set( - DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getPlainTextName(), 0, list, true) +@@ -1009,7 +_,8 @@ + writtenBook.set( + DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getPlainTextName(), 0, pages, true) ); -- this.player.getInventory().setItem(index, itemStack); -+ CraftEventFactory.handleEditBookEvent(this.player, index, item, itemStack); // CraftBukkit -+ this.player.getInventory().setItem(index, item); // CraftBukkit - event factory updates the hand book +- this.player.getInventory().setItem(slot, writtenBook); ++ CraftEventFactory.handleEditBookEvent(this.player, slot, carried, writtenBook); // CraftBukkit ++ this.player.getInventory().setItem(slot, carried); // CraftBukkit - event factory updates the hand book } } -@@ -1022,27 +_,35 @@ - public void handleMovePlayer(ServerboundMovePlayerPacket packet) { +@@ -1057,10 +_,10 @@ + public void handleMovePlayer(final ServerboundMovePlayerPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (containsInvalidValues(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0), packet.getYRot(0.0F), packet.getXRot(0.0F))) { - this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement")); + this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause } else { - ServerLevel serverLevel = this.player.level(); + ServerLevel level = this.player.level(); - if (!this.player.wonGame) { + if (!this.player.wonGame && !this.player.isImmobile()) { // CraftBukkit if (this.tickCount == 0) { this.resetPosition(); } - - if (this.hasClientLoaded()) { -- float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); -- float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); -+ float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); final float toYaw = f; // Paper - OBFHELPER -+ float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); final float toPitch = f1; // Paper - OBFHELPER - if (this.updateAwaitingTeleport()) { - this.player.absSnapRotationTo(f, f1); - } else { -- double d = clampHorizontal(packet.getX(this.player.getX())); -- double d1 = clampVertical(packet.getY(this.player.getY())); -- double d2 = clampHorizontal(packet.getZ(this.player.getZ())); -+ double d = clampHorizontal(packet.getX(this.player.getX())); final double toX = d; // Paper - OBFHELPER -+ double d1 = clampVertical(packet.getY(this.player.getY())); final double toY = d1; // Paper - OBFHELPER -+ double d2 = clampHorizontal(packet.getZ(this.player.getZ())); final double toZ = d2; // Paper - OBFHELPER +@@ -1077,7 +_,15 @@ if (this.player.isPassenger()) { - this.player.absSnapTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); + this.player.absSnapTo(this.player.getX(), this.player.getY(), this.player.getZ(), targetYRot, targetXRot); this.player.level().getChunkSource().move(this.player); + this.allowedPlayerTicks = 20; // CraftBukkit } else { @@ -729,45 +720,47 @@ + float prevYaw = this.player.getYRot(); + float prevPitch = this.player.getXRot(); + // CraftBukkit end - double x = this.player.getX(); - double y = this.player.getY(); - double z = this.player.getZ(); -@@ -1051,6 +_,16 @@ - double d5 = d2 - this.firstGoodZ; - double d6 = this.player.getDeltaMovement().lengthSqr(); - double d7 = d3 * d3 + d4 * d4 + d5 * d5; + double startX = this.player.getX(); + double startY = this.player.getY(); + double startZ = this.player.getZ(); +@@ -1086,6 +_,16 @@ + double zDist = targetZ - this.firstGoodZ; + double expectedDist = this.player.getDeltaMovement().lengthSqr(); + double movedDist = xDist * xDist + yDist * yDist + zDist * zDist; + // Paper start - fix large move vectors killing the server -+ double currDeltaX = toX - prevX; -+ double currDeltaY = toY - prevY; -+ double currDeltaZ = toZ - prevZ; -+ d7 = Math.max(d7, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); -+ double otherFieldX = d - this.lastGoodX; -+ double otherFieldY = d1 - this.lastGoodY; -+ double otherFieldZ = d2 - this.lastGoodZ; -+ d7 = Math.max(d7, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); ++ double currDeltaX = targetX - prevX; ++ double currDeltaY = targetY - prevY; ++ double currDeltaZ = targetZ - prevZ; ++ movedDist = Math.max(movedDist, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); ++ double otherFieldX = targetX - this.lastGoodX; ++ double otherFieldY = targetY - this.lastGoodY; ++ double otherFieldZ = targetZ - this.lastGoodZ; ++ movedDist = Math.max(movedDist, (otherFieldX * otherFieldX + otherFieldY * otherFieldY + otherFieldZ * otherFieldZ) - 1); + // Paper end - fix large move vectors killing the server if (this.player.isSleeping()) { - if (d7 > 1.0) { - this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); -@@ -1060,36 +_,108 @@ - if (serverLevel.tickRateManager().runsNormally()) { + if (movedDist > 1.0) { + this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), targetYRot, targetXRot); +@@ -1095,7 +_,13 @@ + if (level.tickRateManager().runsNormally()) { this.receivedMovePacketCount++; - int i = this.receivedMovePacketCount - this.knownMovePacketCount; -- if (i > 5) { + int deltaPackets = this.receivedMovePacketCount - this.knownMovePacketCount; +- if (deltaPackets > 5) { + // CraftBukkit start - handle custom speeds and skipped ticks + this.allowedPlayerTicks += (System.currentTimeMillis() / 50) - this.lastTick; + this.allowedPlayerTicks = Math.max(this.allowedPlayerTicks, 1); + this.lastTick = (int) (System.currentTimeMillis() / 50); + -+ if (i > Math.max(this.allowedPlayerTicks, 5)) { ++ if (deltaPackets > Math.max(this.allowedPlayerTicks, 5)) { + // CraftBukkit end LOGGER.debug( - "{} is sending move packets too frequently ({} packets since last tick)", this.player.getPlainTextName(), i + "{} is sending move packets too frequently ({} packets since last tick)", + this.player.getPlainTextName(), +@@ -1103,30 +_,96 @@ ); - i = 1; + deltaPackets = 1; } + // CraftBukkit start - handle custom speeds and skipped ticks -+ if (packet.hasRot || d7 > 0) { ++ if (packet.hasRot || movedDist > 0) { + this.allowedPlayerTicks -= 1; + } else { + this.allowedPlayerTicks = 20; @@ -779,10 +772,10 @@ + speed = this.player.getAbilities().walkingSpeed * 10f; + } + // Paper start - Prevent moving into unloaded chunks -+ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != toX || this.player.getZ() != toZ) && !serverLevel.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(toX, toY, toZ).subtract(this.player.position())))) { ++ if (this.player.level().paperConfig().chunks.preventMovingIntoUnloadedChunks && (this.player.getX() != targetX || this.player.getZ() != targetZ) && !level.areChunksLoadedForMove(this.player.getBoundingBox().expandTowards(new Vec3(targetX, targetY, targetZ).subtract(this.player.position())))) { + // Paper start - Add fail move event + io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_INTO_UNLOADED_CHUNK, -+ toX, toY, toZ, toYaw, toPitch, false); ++ targetX, targetY, targetZ, targetYRot, targetXRot, false); + if (!event.isAllowed()) { + this.internalTeleport(PositionMoveRotation.of(this.player), Collections.emptySet()); + return; @@ -792,16 +785,16 @@ + // Paper end - Prevent moving into unloaded chunks if (this.shouldCheckPlayerMovement(isFallFlying)) { - float f2 = isFallFlying ? 300.0F : 100.0F; -- if (d7 - d6 > f2 * i) { -+ if (d7 - d6 > Math.max(f2, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed))) { + float metersPerTick = isFallFlying ? 300.0F : 100.0F; +- if (movedDist - expectedDist > metersPerTick * deltaPackets) { ++ if (movedDist - expectedDist > Math.max(metersPerTick, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) deltaPackets * speed))) { + // CraftBukkit end + // Paper start - Add fail move event + io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY, -+ toX, toY, toZ, toYaw, toPitch, true); ++ targetX, targetY, targetZ, targetYRot, targetXRot, true); + if (!event.isAllowed()) { + if (event.getLogWarning()) { - LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getPlainTextName(), d3, d4, d5); + LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getPlainTextName(), xDist, yDist, zDist); - this.teleport( - this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot() - ); @@ -817,15 +810,15 @@ } } - AABB boundingBox = this.player.getBoundingBox(); -- d3 = d - this.lastGoodX; -- d4 = d1 - this.lastGoodY; -- d5 = d2 - this.lastGoodZ; -+ d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above -+ d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above -+ d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above - boolean flag = d4 > 0.0; - if (this.player.onGround() && !packet.isOnGround() && flag) { + AABB oldAABB = this.player.getBoundingBox(); +- xDist = targetX - this.lastGoodX; +- yDist = targetY - this.lastGoodY; +- zDist = targetZ - this.lastGoodZ; ++ xDist = targetX - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above ++ yDist = targetY - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above ++ zDist = targetZ - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above + boolean movedUpwards = yDist > 0.0; + if (this.player.onGround() && !packet.isOnGround() && movedUpwards) { - this.player.jumpFromGround(); + // Paper start - Add PlayerJumpEvent + org.bukkit.entity.Player player = this.getCraftPlayer(); @@ -857,34 +850,34 @@ + // Paper end - Add PlayerJumpEvent } - boolean flag1 = this.player.verticalCollisionBelow; - this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); + boolean playerStandsOnSomething = this.player.verticalCollisionBelow; + this.player.move(MoverType.PLAYER, new Vec3(xDist, yDist, zDist)); + this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move + // Paper start - prevent position desync + if (this.awaitingPositionFromClient != null) { + return; // ... thanks Mojang for letting move calls teleport across dimensions. + } + // Paper end - prevent position desync - double verticalDelta = d4; - d3 = d - this.player.getX(); - d4 = d1 - this.player.getY(); -@@ -1099,21 +_,101 @@ - - d5 = d2 - this.player.getZ(); - d7 = d3 * d3 + d4 * d4 + d5 * d5; -- boolean flag2 = false; + double oyDist = yDist; + xDist = targetX - this.player.getX(); + yDist = targetY - this.player.getY(); +@@ -1136,21 +_,101 @@ + + zDist = targetZ - this.player.getZ(); + movedDist = xDist * xDist + yDist * yDist + zDist * zDist; +- boolean fail = false; + boolean movedWrongly = false; // Paper - Add fail move event; rename if (!this.player.isChangingDimension() -- && d7 > 0.0625 -+ && d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold // Spigot +- && movedDist > 0.0625 ++ && movedDist > org.spigotmc.SpigotConfig.movedWronglyThreshold // Spigot && !this.player.isSleeping() && !this.player.isCreative() && !this.player.isSpectator() && !this.player.isInPostImpulseGraceTime()) { -- flag2 = true; +- fail = true; + // Paper start - Add fail move event + io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_WRONGLY, -+ toX, toY, toZ, toYaw, toPitch, true); ++ targetX, targetY, targetZ, targetYRot, targetXRot, true); + if (!event.isAllowed()) { + movedWrongly = true; + if (event.getLogWarning()) @@ -894,16 +887,16 @@ - - if (this.player.noPhysics - || this.player.isSleeping() -- || (!flag2 || !serverLevel.noCollision(this.player, boundingBox)) -- && !this.isEntityCollidingWithAnythingNew(serverLevel, this.player, boundingBox, d, d1, d2)) { +- || (!fail || !level.noCollision(this.player, oldAABB)) +- && !this.isEntityCollidingWithAnythingNew(level, this.player, oldAABB, targetX, targetY, targetZ)) { + } // Paper + } + + // Paper start - Add fail move event -+ boolean allowMovement = this.player.noPhysics || this.player.isSleeping() || (!movedWrongly || !serverLevel.noCollision(this.player, boundingBox)) && !this.isEntityCollidingWithAnythingNew(serverLevel, this.player, boundingBox, d, d1, d2); ++ boolean allowMovement = this.player.noPhysics || this.player.isSleeping() || (!movedWrongly || !level.noCollision(this.player, oldAABB)) && !this.isEntityCollidingWithAnythingNew(level, this.player, oldAABB, targetX, targetY, targetZ); + if (!allowMovement) { + io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, -+ toX, toY, toZ, toYaw, toPitch, false); ++ targetX, targetY, targetZ, targetYRot, targetXRot, false); + if (event.isAllowed()) { + allowMovement = true; + } @@ -976,19 +969,19 @@ + } + } + // Paper end - this.player.absSnapTo(d, d1, d2, f, f1); + this.player.absSnapTo(targetX, targetY, targetZ, targetYRot, targetXRot); boolean isAutoSpinAttack = this.player.isAutoSpinAttack(); - this.clientIsFloating = verticalDelta >= -0.03125 -@@ -1148,7 +_,7 @@ + this.clientIsFloating = oyDist >= -0.03125 +@@ -1185,7 +_,7 @@ this.lastGoodY = this.player.getY(); this.lastGoodZ = this.player.getZ(); } else { -- this.teleport(x, y, z, f, f1); -+ this.internalTeleport(x, y, z, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet. - this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround()); - this.player.removeLatestMovementRecording(); - } -@@ -1183,6 +_,7 @@ +- this.teleport(startX, startY, startZ, targetYRot, targetXRot); ++ this.internalTeleport(startX, startY, startZ, targetYRot, targetXRot); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet. + this.player + .doCheckFallDamage( + this.player.getX() - startX, this.player.getY() - startY, this.player.getZ() - startZ, packet.isOnGround() +@@ -1223,6 +_,7 @@ this.player.getXRot() ); } @@ -996,10 +989,10 @@ return true; } else { -@@ -1206,10 +_,77 @@ +@@ -1248,10 +_,77 @@ } - public void teleport(double x, double y, double z, float yRot, float xRot) { + public void teleport(final double x, final double y, final double z, final float yRot, final float xRot) { - this.teleport(new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yRot, xRot), Collections.emptySet()); + // CraftBukkit start + this.teleport(x, y, z, yRot, xRot, PlayerTeleportEvent.TeleportCause.UNKNOWN); @@ -1010,19 +1003,19 @@ + // CraftBukkit end } - public void teleport(PositionMoveRotation posMoveRotation, Set relatives) { + public void teleport(final PositionMoveRotation destination, final Set relatives) { + // CraftBukkit start -+ this.teleport(posMoveRotation, relatives, PlayerTeleportEvent.TeleportCause.UNKNOWN); ++ this.teleport(destination, relatives, PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + -+ public boolean teleport(PositionMoveRotation posMoveRotation, Set relatives, PlayerTeleportEvent.TeleportCause cause) { // CraftBukkit - Return event status ++ public boolean teleport(PositionMoveRotation destination, Set relatives, PlayerTeleportEvent.TeleportCause cause) { // CraftBukkit - Return event status + org.bukkit.entity.Player player = this.getCraftPlayer(); + Location from = player.getLocation(); -+ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this.player), posMoveRotation, relatives); ++ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this.player), destination, relatives); + Location to = CraftLocation.toBukkit(absolutePosition.position(), this.player.level(), absolutePosition.yRot(), absolutePosition.xRot()); + // SPIGOT-5171: Triggered on join + if (from.equals(to)) { -+ this.internalTeleport(posMoveRotation, relatives); ++ this.internalTeleport(destination, relatives); + return true; // CraftBukkit - Return event status + } + @@ -1039,10 +1032,10 @@ + if (event.isCancelled() || !to.equals(event.getTo())) { + relatives = Set.of(); // target pos is absolute + to = event.isCancelled() ? event.getFrom() : event.getTo(); -+ posMoveRotation = new PositionMoveRotation(CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch()); ++ destination = new PositionMoveRotation(CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch()); + } + -+ this.internalTeleport(posMoveRotation, relatives); ++ this.internalTeleport(destination, relatives); + return !event.isCancelled(); // CraftBukkit - Return event status + } + @@ -1054,20 +1047,20 @@ + this.internalTeleport(new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yRot, xRot), Collections.emptySet()); + } + -+ public void internalTeleport(PositionMoveRotation posMoveRotation, Set relatives) { ++ public void internalTeleport(PositionMoveRotation destination, Set relatives) { + org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper + // Paper start - Prevent teleporting dead entities + if (this.player.isRemoved()) { -+ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); ++ LOGGER.info("Attempt to teleport removed player {} restricted", this.player.getScoreboardName()); + if (this.server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player"); + return; + } + // Paper end - Prevent teleporting dead entities -+ if (Float.isNaN(posMoveRotation.yRot())) { -+ posMoveRotation = new PositionMoveRotation(posMoveRotation.position(), posMoveRotation.deltaMovement(), 0, posMoveRotation.xRot()); ++ if (Float.isNaN(destination.yRot())) { ++ destination = new PositionMoveRotation(destination.position(), destination.deltaMovement(), 0, destination.xRot()); + } -+ if (Float.isNaN(posMoveRotation.xRot())) { -+ posMoveRotation = new PositionMoveRotation(posMoveRotation.position(), posMoveRotation.deltaMovement(), posMoveRotation.yRot(), 0); ++ if (Float.isNaN(destination.xRot())) { ++ destination = new PositionMoveRotation(destination.position(), destination.deltaMovement(), destination.yRot(), 0); + } + + this.justTeleported = true; @@ -1075,9 +1068,9 @@ this.awaitingTeleportTime = this.tickCount; if (++this.awaitingTeleport == Integer.MAX_VALUE) { this.awaitingTeleport = 0; -@@ -1217,12 +_,20 @@ +@@ -1259,12 +_,20 @@ - this.player.teleportSetPosition(posMoveRotation, relatives); + this.player.teleportSetPosition(destination, relatives); this.awaitingPositionFromClient = this.player.position(); + // CraftBukkit start - update last location + this.lastPosX = this.awaitingPositionFromClient.x; @@ -1086,24 +1079,24 @@ + this.lastYaw = this.player.getYRot(); + this.lastPitch = this.player.getXRot(); + // CraftBukkit end - this.send(ClientboundPlayerPositionPacket.of(this.awaitingTeleport, posMoveRotation, relatives)); + this.send(ClientboundPlayerPositionPacket.of(this.awaitingTeleport, destination, relatives)); } @Override - public void handlePlayerAction(ServerboundPlayerActionPacket packet) { + public void handlePlayerAction(final ServerboundPlayerActionPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit if (this.hasClientLoaded()) { BlockPos pos = packet.getPos(); this.player.resetLastActionTime(); -@@ -1247,32 +_,95 @@ +@@ -1289,32 +_,95 @@ case SWAP_ITEM_WITH_OFFHAND: if (!this.player.isSpectator()) { - ItemStack itemInHand1 = this.player.getItemInHand(InteractionHand.OFF_HAND); + ItemStack swap = this.player.getItemInHand(InteractionHand.OFF_HAND); - this.player.setItemInHand(InteractionHand.OFF_HAND, this.player.getItemInHand(InteractionHand.MAIN_HAND)); -- this.player.setItemInHand(InteractionHand.MAIN_HAND, itemInHand1); +- this.player.setItemInHand(InteractionHand.MAIN_HAND, swap); + // CraftBukkit start - inspiration taken from DispenserRegistry (See SpigotCraft#394) -+ CraftItemStack mainHand = CraftItemStack.asCraftMirror(itemInHand1); ++ CraftItemStack mainHand = CraftItemStack.asCraftMirror(swap); + CraftItemStack offHand = CraftItemStack.asCraftMirror(this.player.getItemInHand(InteractionHand.MAIN_HAND)); + PlayerSwapHandItemsEvent swapItemsEvent = new PlayerSwapHandItemsEvent(this.getCraftPlayer(), mainHand.clone(), offHand.clone()); + this.cserver.getPluginManager().callEvent(swapItemsEvent); @@ -1116,7 +1109,7 @@ + this.player.setItemInHand(InteractionHand.OFF_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getOffHandItem())); + } + if (swapItemsEvent.getMainHandItem().equals(mainHand)) { -+ this.player.setItemInHand(InteractionHand.MAIN_HAND, itemInHand1); ++ this.player.setItemInHand(InteractionHand.MAIN_HAND, swap); + } else { + this.player.setItemInHand(InteractionHand.MAIN_HAND, CraftItemStack.asNMSCopy(swapItemsEvent.getMainHandItem())); + } @@ -1194,7 +1187,7 @@ return; default: throw new IllegalArgumentException("Invalid player action"); -@@ -1290,9 +_,36 @@ +@@ -1332,9 +_,36 @@ } } @@ -1224,111 +1217,111 @@ + // Paper end - limit place/interactions + @Override - public void handleUseItemOn(ServerboundUseItemOnPacket packet) { + public void handleUseItemOn(final ServerboundUseItemOnPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit + if (!this.checkLimit(packet.timestamp)) return; // Spigot - check limit if (this.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); - ServerLevel serverLevel = this.player.level(); -@@ -1301,6 +_,11 @@ - if (itemInHand.isItemEnabled(serverLevel.enabledFeatures())) { - BlockHitResult hitResult = packet.getHitResult(); - Vec3 location = hitResult.getLocation(); + ServerLevel level = this.player.level(); +@@ -1343,6 +_,11 @@ + if (itemStack.isItemEnabled(level.enabledFeatures())) { + BlockHitResult blockHit = packet.getHitResult(); + Vec3 location = blockHit.getLocation(); + // Paper start - improve distance check -+ if (!Double.isFinite(location.x()) || !Double.isFinite(location.y()) || !Double.isFinite(location.z())) { ++ if (!location.isFinite()) { + return; + } + // Paper end - improve distance check - BlockPos blockPos = hitResult.getBlockPos(); - if (this.player.isWithinBlockInteractionRange(blockPos, 1.0)) { - Vec3 vec3 = location.subtract(Vec3.atCenterOf(blockPos)); -@@ -1310,7 +_,8 @@ - this.player.resetLastActionTime(); - int maxY = this.player.level().getMaxY(); - if (blockPos.getY() <= maxY) { -- if (this.awaitingPositionFromClient == null && serverLevel.mayInteract(this.player, blockPos)) { -+ if (this.awaitingPositionFromClient == null && (serverLevel.mayInteract(this.player, blockPos) || (serverLevel.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && serverLevel.getBlockState(blockPos).getBlock() instanceof net.minecraft.world.level.block.SignBlock))) { // Paper - Allow using signs inside spawn protection + BlockPos pos = blockHit.getBlockPos(); + if (this.player.isWithinBlockInteractionRange(pos, 1.0)) { + Vec3 distance = location.subtract(Vec3.atCenterOf(pos)); +@@ -1357,9 +_,13 @@ + } else if (pos.getY() < minY) { + this.player.sendBuildLimitMessage(false, minY); + } else { +- if (this.server.isUnderSpawnProtection(level, pos, this.player)) { ++ // Paper start - Allow using signs inside spawn protection ++ final boolean passthroughSignInteraction = (level.paperConfig().spawn.allowUsingSignsInsideSpawnProtection && level.getBlockState(pos).getBlock() instanceof net.minecraft.world.level.block.SignBlock); ++ if (!passthroughSignInteraction && this.server.isUnderSpawnProtection(level, pos, this.player)) { + this.player.sendSpawnProtectionMessage(pos); +- } else if (this.awaitingPositionFromClient == null && level.mayInteract(this.player, pos)) { ++ } else if (this.awaitingPositionFromClient == null && (level.mayInteract(this.player, pos) || passthroughSignInteraction)) { ++ // Paper end - Allow using signs inside spawn protection + this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706 - InteractionResult interactionResult = this.player.gameMode.useItemOn(this.player, serverLevel, itemInHand, hand, hitResult); + InteractionResult interactionResult = this.player.gameMode.useItemOn(this.player, level, itemStack, hand, blockHit); if (interactionResult.consumesAction()) { - CriteriaTriggers.ANY_BLOCK_USE.trigger(this.player, hitResult.getBlockPos(), itemInHand.copy()); -@@ -1323,10 +_,19 @@ - Component component = Component.translatable("build.tooHigh", maxY).withStyle(ChatFormatting.RED); - this.player.sendSystemMessage(component, true); + CriteriaTriggers.ANY_BLOCK_USE.trigger(this.player, blockHit.getBlockPos(), itemStack); +@@ -1371,7 +_,7 @@ + && wasBlockPlacementAttempt(this.player, itemStack)) { + this.player.sendBuildLimitMessage(true, maxY); } else if (interactionResult instanceof InteractionResult.Success success - && success.swingSource() == InteractionResult.SwingSource.SERVER) { + && success.swingSource() == InteractionResult.SwingSource.SERVER && !this.player.gameMode.interactResult) { // Paper - Call interact event this.player.swing(hand, true); } + +@@ -1385,6 +_,15 @@ + && success.swingSource() == InteractionResult.SwingSource.SERVER) { + this.player.swing(hand, true); + } + // Paper start - Fix inventory desync; MC-99075 -+ // From serverLevel.mayInteract(this.player, blockPos) -+ } else if (this.server.isUnderSpawnProtection(serverLevel, blockPos, player)) { -+ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, serverLevel.getBlockState(blockPos), itemInHand)) { ++ // From level.mayInteract(this.player, pos) ++ } else if (this.server.isUnderSpawnProtection(level, pos, player)) { ++ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, level.getBlockState(pos), itemStack)) { + this.player.containerMenu.sendAllDataToRemote(); + } else { + this.player.containerMenu.forceHeldSlot(hand); + } - } + // Paper end - Fix inventory desync - } else { - Component component1 = Component.translatable("build.tooHigh", maxY).withStyle(ChatFormatting.RED); - this.player.sendSystemMessage(component1, true); -@@ -1334,13 +_,8 @@ - - this.send(new ClientboundBlockUpdatePacket(serverLevel, blockPos)); - this.send(new ClientboundBlockUpdatePacket(serverLevel, blockPos.relative(direction))); + } else { + this.player.sendBuildLimitMessage(true, maxY); + } +@@ -1392,13 +_,8 @@ + this.send(new ClientboundBlockUpdatePacket(level, pos)); + this.send(new ClientboundBlockUpdatePacket(level, pos.relative(direction))); + } - } else { - LOGGER.warn( - "Rejecting UseItemOnPacket from {}: Location {} too far away from hit block {}.", - this.player.getGameProfile().name(), - location, -- blockPos +- pos - ); + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes. + // Paper - Remove unused warning } } } -@@ -1350,6 +_,8 @@ +@@ -1408,6 +_,8 @@ @Override - public void handleUseItem(ServerboundUseItemPacket packet) { + public void handleUseItem(final ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit + if (!this.checkLimit(packet.timestamp)) return; // Spigot - check limit if (this.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); - ServerLevel serverLevel = this.player.level(); -@@ -1363,6 +_,54 @@ - this.player.absSnapRotationTo(f, f1); + ServerLevel level = this.player.level(); +@@ -1421,6 +_,44 @@ + this.player.absSnapRotationTo(targetYRot, targetXRot); } + // CraftBukkit start + // Raytrace to look for 'rogue armswings' -+ double x = this.player.getX(); -+ double eyeY = this.player.getEyeY(); -+ double z = this.player.getZ(); -+ Vec3 from = new Vec3(x, eyeY, z); -+ -+ float f3 = Mth.cos(-f * 0.017453292F - 3.1415927F); -+ float f4 = Mth.sin(-f * 0.017453292F - 3.1415927F); -+ float f5 = -Mth.cos(-f1 * 0.017453292F); -+ float f6 = Mth.sin(-f1 * 0.017453292F); -+ float f7 = f4 * f5; -+ float f8 = f3 * f5; -+ double d3 = this.player.blockInteractionRange(); -+ Vec3 to = from.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); ++ Vec3 from = this.player.getEyePosition(); ++ Vec3 delta = this.player.getViewVector(1.0F).scale(this.player.blockInteractionRange()); ++ Vec3 to = from.add(delta); + BlockHitResult hitResult = this.player.level().clip(new net.minecraft.world.level.ClipContext(from, to, net.minecraft.world.level.ClipContext.Block.OUTLINE, net.minecraft.world.level.ClipContext.Fluid.NONE, this.player)); + + boolean cancelled; + if (hitResult == null || hitResult.getType() != HitResult.Type.BLOCK) { -+ org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemInHand, hand); ++ org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemStack, hand); + cancelled = event.useItemInHand() == Event.Result.DENY; + } else { -+ if (this.player.gameMode.firedInteract && this.player.gameMode.interactPosition.equals(hitResult.getBlockPos()) && this.player.gameMode.interactHand == hand && ItemStack.isSameItemSameComponents(this.player.gameMode.interactItemStack, itemInHand)) { ++ if (this.player.gameMode.firedInteract && this.player.gameMode.interactPosition.equals(hitResult.getBlockPos()) && this.player.gameMode.interactHand == hand && ItemStack.isSameItemSameComponents(this.player.gameMode.interactItemStack, itemStack)) { + cancelled = this.player.gameMode.interactResult; + } else { -+ org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_BLOCK, hitResult.getBlockPos(), hitResult.getDirection(), itemInHand, true, hand, hitResult.getLocation()); ++ org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_BLOCK, hitResult.getBlockPos(), hitResult.getDirection(), itemStack, true, hand, hitResult.getLocation()); + cancelled = event.useItemInHand() == Event.Result.DENY; + } + this.player.gameMode.firedInteract = false; @@ -1337,7 +1330,7 @@ + if (cancelled) { + this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items + // Paper start - Fix inventory desync; SPIGOT-2524 -+ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), itemInHand)) { ++ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(this.player, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), itemStack)) { + this.player.containerMenu.sendAllDataToRemote(); + } else { + this.player.containerMenu.forceHeldSlotAndArmor(hand); @@ -1345,28 +1338,28 @@ + // Paper end - Fix inventory desync + return; + } -+ itemInHand = this.player.getItemInHand(hand); // Update in case it was changed in the event -+ if (itemInHand.isEmpty()) { ++ itemStack = this.player.getItemInHand(hand); // Update in case it was changed in the event ++ if (itemStack.isEmpty()) { + return; + } + // CraftBukkit end + - if (this.player.gameMode.useItem(this.player, serverLevel, itemInHand, hand) instanceof InteractionResult.Success success + if (this.player.gameMode.useItem(this.player, level, itemStack, hand) instanceof InteractionResult.Success success && success.swingSource() == InteractionResult.SwingSource.SERVER) { this.player.swing(hand, true); -@@ -1378,7 +_,7 @@ - for (ServerLevel serverLevel : this.server.getAllLevels()) { - Entity entity = packet.getEntity(serverLevel); +@@ -1436,7 +_,7 @@ + for (ServerLevel level : this.server.getAllLevels()) { + Entity entity = packet.getEntity(level); if (entity != null) { -- this.player.teleportTo(serverLevel, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true); -+ this.player.teleportTo(serverLevel, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit +- this.player.teleportTo(level, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true); ++ this.player.teleportTo(level, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit return; } } -@@ -1395,24 +_,50 @@ +@@ -1453,24 +_,50 @@ @Override - public void onDisconnect(DisconnectionDetails details) { + public void onDisconnect(final DisconnectionDetails details) { + // CraftBukkit start - Rarely it would send a disconnect line twice + if (this.processedDisconnect) { + return; @@ -1410,15 +1403,15 @@ this.player.getTextFilter().leave(); } - public void ackBlockChangesUpTo(int sequence) { - if (sequence < 0) { + public void ackBlockChangesUpTo(final int packetSequenceNr) { + if (packetSequenceNr < 0) { + this.disconnect(Component.literal("Expected packet sequence nr >= 0"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - Treat sequence violations like they should be throw new IllegalArgumentException("Expected packet sequence nr >= 0"); } else { - this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo); -@@ -1422,20 +_,38 @@ + this.ackBlockChangesUpTo = Math.max(packetSequenceNr, this.ackBlockChangesUpTo); +@@ -1480,20 +_,38 @@ @Override - public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { + public void handleSetCarriedItem(final ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit if (packet.getSlot() >= 0 && packet.getSlot() < Inventory.getSelectionSize()) { @@ -1445,30 +1438,30 @@ } @Override - public void handleChat(ServerboundChatPacket packet) { + public void handleChat(final ServerboundChatPacket packet) { + // CraftBukkit start - async chat + // SPIGOT-3638 + if (this.server.isStopped()) { + return; + } + // CraftBukkit end - Optional optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); - if (!optional.isEmpty()) { + Optional unpackedLastSeen = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); + if (!unpackedLastSeen.isEmpty()) { this.tryHandleChat(packet.message(), false, () -> { -@@ -1447,25 +_,45 @@ +@@ -1505,25 +_,45 @@ return; } -- CompletableFuture completableFuture = this.filterTextPacket(signedMessage.signedContent()); -- Component component = this.server.getChatDecorator().decorate(this.player, signedMessage.decoratedContent()); -- this.chatMessageChain.append(completableFuture, filteredText -> { -- PlayerChatMessage playerChatMessage = signedMessage.withUnsignedContent(component).filter(filteredText.mask()); -+ CompletableFuture completableFuture = this.filterTextPacket(signedMessage.signedContent()).thenApplyAsync(java.util.function.Function.identity(), this.server.chatExecutor); // CraftBukkit - async chat -+ CompletableFuture componentFuture = this.server.getChatDecorator().decorate(this.player, null, signedMessage.decoratedContent()); // Paper - Adventure +- CompletableFuture filteredFuture = this.filterTextPacket(signedMessage.signedContent()); +- Component decorated = this.server.getChatDecorator().decorate(this.player, signedMessage.decoratedContent()); +- this.chatMessageChain.append(filteredFuture, filtered -> { +- PlayerChatMessage filteredMessage = signedMessage.withUnsignedContent(decorated).filter(filtered.mask()); ++ CompletableFuture filteredFuture = this.filterTextPacket(signedMessage.signedContent()).thenApplyAsync(java.util.function.Function.identity(), this.server.chatExecutor); // CraftBukkit - async chat ++ CompletableFuture decoratedFuture = this.server.getChatDecorator().decorate(this.player, null, signedMessage.decoratedContent()); // Paper - Adventure + -+ this.chatMessageChain.append(CompletableFuture.allOf(completableFuture, componentFuture), ($) -> { // Paper - Adventure -+ PlayerChatMessage playerChatMessage = signedMessage.withUnsignedContent(componentFuture.join()).filter(completableFuture.join().mask()); // Paper - Adventure - this.broadcastChatMessage(playerChatMessage); ++ this.chatMessageChain.append(CompletableFuture.allOf(filteredFuture, decoratedFuture), ($) -> { // Paper - Adventure ++ PlayerChatMessage filteredMessage = signedMessage.withUnsignedContent(decoratedFuture.join()).filter(filteredFuture.join().mask()); // Paper - Adventure + this.broadcastChatMessage(filteredMessage); }); - }); + }, false); // CraftBukkit - async chat @@ -1476,7 +1469,7 @@ } @Override - public void handleChatCommand(ServerboundChatCommandPacket packet) { + public void handleChatCommand(final ServerboundChatCommandPacket packet) { this.tryHandleChat(packet.command(), true, () -> { + // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands + if (this.player.hasDisconnected()) { @@ -1490,8 +1483,9 @@ + }, true); // CraftBukkit - sync commands } - private void performUnsignedChatCommand(String command) { -+ // CraftBukkit start +- private void performUnsignedChatCommand(final String command) { ++ // CraftBukkit start ++ private void performUnsignedChatCommand(String command) { + String prefixedCommand = "/" + command; + if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check + LOGGER.info("{} issued server command: {}", this.player.getScoreboardName(), prefixedCommand); @@ -1505,19 +1499,19 @@ + } + command = event.getMessage().substring(1); + // CraftBukkit end - ParseResults parseResults = this.parseCommand(command); - if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseResults)) { + ParseResults parsed = this.parseCommand(command); + if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parsed)) { LOGGER.error( -@@ -1482,28 +_,57 @@ - Optional optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); - if (!optional.isEmpty()) { +@@ -1540,26 +_,55 @@ + Optional unpackedLastSeen = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); + if (!unpackedLastSeen.isEmpty()) { this.tryHandleChat(packet.command(), true, () -> { + // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands + if (this.player.hasDisconnected()) { + return; + } + // CraftBukkit end - this.performSignedChatCommand(packet, optional.get()); + this.performSignedChatCommand(packet, unpackedLastSeen.get()); - this.detectRateSpam(); - }); + this.detectRateSpam("/" + packet.command()); // Spigot @@ -1525,23 +1519,23 @@ } } - private void performSignedChatCommand(ServerboundChatCommandSignedPacket packet, LastSeenMessages lastSeenMessages) { + private void performSignedChatCommand(final ServerboundChatCommandSignedPacket packet, final LastSeenMessages lastSeenMessages) { + // CraftBukkit start -+ String command = "/" + packet.command(); ++ String commandString = "/" + packet.command(); + if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check -+ LOGGER.info("{} issued server command: {}", this.player.getScoreboardName(), command); ++ LOGGER.info("{} issued server command: {}", this.player.getScoreboardName(), commandString); + } // Paper - Add missing SpigotConfig logCommands check + -+ PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(this.server)); ++ PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), commandString, new org.bukkit.craftbukkit.util.LazyPlayerSet(this.server)); + this.cserver.getPluginManager().callEvent(event); -+ command = event.getMessage().substring(1); ++ commandString = event.getMessage().substring(1); + - ParseResults parseResults = this.parseCommand(packet.command()); + ParseResults command = this.parseCommand(packet.command()); - Map map; + Map signedArguments; try { + // Paper - Always parse the original command to add to the chat chain - map = this.collectSignedArguments(packet, SignableCommand.of(parseResults), lastSeenMessages); + signedArguments = this.collectSignedArguments(packet, SignableCommand.of(command), lastSeenMessages); } catch (SignedMessageChain.DecodeException var6) { this.handleMessageDecodeFailure(var6); return; @@ -1554,48 +1548,46 @@ + } + + // Remove signed parts if the command was changed -+ if (!command.equals(packet.command())) { -+ parseResults = this.parseCommand(command); -+ map = Collections.emptyMap(); ++ if (!commandString.equals(packet.command())) { ++ command = this.parseCommand(commandString); ++ signedArguments = Collections.emptyMap(); + } + // Paper end - Fix cancellation and message changing + - CommandSigningContext commandSigningContext = new CommandSigningContext.SignedArguments(map); - parseResults = Commands.mapSource( - parseResults, commandSourceStack -> commandSourceStack.withSigningContext(commandSigningContext, this.chatMessageChain) - ); -- this.server.getCommands().performCommand(parseResults, packet.command()); -+ this.server.getCommands().performCommand(parseResults, command); // CraftBukkit + CommandSigningContext signingContext = new CommandSigningContext.SignedArguments(signedArguments); + command = Commands.mapSource(command, source -> source.withSigningContext(signingContext, this.chatMessageChain)); +- this.server.getCommands().performCommand(command, packet.command()); ++ this.server.getCommands().performCommand(command, commandString); // CraftBukkit } - private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { -@@ -1567,14 +_,20 @@ - return dispatcher.parse(command, this.player.createCommandSourceStack()); + private void handleMessageDecodeFailure(final SignedMessageChain.DecodeException e) { +@@ -1623,14 +_,20 @@ + return commands.parse(command, this.player.createCommandSourceStack()); } -- private void tryHandleChat(String message, boolean bypassHiddenChat, Runnable handler) { -+ private void tryHandleChat(String message, boolean bypassHiddenChat, Runnable handler, boolean sync) { // CraftBukkit +- private void tryHandleChat(final String message, final boolean isCommand, final Runnable chatHandler) { ++ private void tryHandleChat(final String message, final boolean isCommand, final Runnable chatHandler, final boolean sync) { // CraftBukkit if (isChatMessageIllegal(message)) { - this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters")); -- } else if (!bypassHiddenChat && this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { +- } else if (!isCommand && this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { + this.disconnectAsync(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add proper async disconnect -+ } else if (this.player.isRemoved() || (!bypassHiddenChat && this.player.getChatVisibility() == ChatVisiblity.HIDDEN)) { // CraftBukkit - dead men tell no tales ++ } else if (this.player.isRemoved() || (!isCommand && this.player.getChatVisibility() == ChatVisiblity.HIDDEN)) { // CraftBukkit - dead men tell no tales this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false)); } else { this.player.resetLastActionTime(); -- this.server.execute(handler); +- this.server.execute(chatHandler); + // CraftBukkit start + if (sync) { -+ this.server.execute(handler); ++ this.server.execute(chatHandler); + } else { -+ handler.run(); ++ chatHandler.run(); + } + // CraftBukkit end } } -@@ -1586,7 +_,7 @@ - var10000 = Optional.of(lastSeenMessages); +@@ -1642,7 +_,7 @@ + var10000 = Optional.of(result); } catch (LastSeenMessagesValidator.ValidationException var5) { LOGGER.error("Failed to validate message acknowledgements from {}: {}", this.player.getPlainTextName(), var5.getMessage()); - this.disconnect(CHAT_VALIDATION_FAILED); @@ -1603,7 +1595,7 @@ return Optional.empty(); } -@@ -1604,22 +_,81 @@ +@@ -1660,22 +_,81 @@ return false; } @@ -1642,12 +1634,12 @@ + } + // CraftBukkit end + - private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { - SignedMessageBody signedMessageBody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); - return this.signedMessageDecoder.unpack(packet.signature(), signedMessageBody); + private PlayerChatMessage getSignedMessage(final ServerboundChatPacket packet, final LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { + SignedMessageBody body = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); + return this.signedMessageDecoder.unpack(packet.signature(), body); } - private void broadcastChatMessage(PlayerChatMessage message) { + private void broadcastChatMessage(final PlayerChatMessage message) { - this.server.getPlayerList().broadcastChatMessage(message, this.player, ChatType.bind(ChatType.CHAT, this.player)); - this.detectRateSpam(); + // CraftBukkit start @@ -1691,7 +1683,7 @@ } } -@@ -1630,7 +_,7 @@ +@@ -1686,7 +_,7 @@ this.lastSeenMessages.applyOffset(packet.offset()); } catch (LastSeenMessagesValidator.ValidationException var5) { LOGGER.error("Failed to validate message acknowledgement offset from {}: {}", this.player.getPlainTextName(), var5.getMessage()); @@ -1700,24 +1692,18 @@ } } } -@@ -1638,7 +_,40 @@ +@@ -1694,7 +_,34 @@ @Override - public void handleAnimate(ServerboundSwingPacket packet) { + public void handleAnimate(final ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit this.player.resetLastActionTime(); + // CraftBukkit start - Raytrace to look for 'rogue armswings' -+ float f1 = this.player.getXRot(); -+ float f2 = this.player.getYRot(); -+ double d0 = this.player.getX(); -+ double d1 = this.player.getY() + (double) this.player.getEyeHeight(); -+ double d2 = this.player.getZ(); -+ Location origin = new Location(this.player.level().getWorld(), d0, d1, d2, f2, f1); -+ -+ double d3 = Math.max(this.player.blockInteractionRange(), this.player.entityInteractionRange()); ++ Location origin = CraftLocation.toBukkit(this.player.getEyePosition(), this.player.level(), this.player.getYRot(), this.player.getXRot()); ++ double maxRange = Math.max(this.player.blockInteractionRange(), this.player.entityInteractionRange()); // todo flawed + // SPIGOT-5607: Only call interact event if no block or entity is being clicked. Use bukkit ray trace method, because it handles blocks and entities at the same time + // SPIGOT-7429: Make sure to call PlayerInteractEvent for spectators and non-pickable entities -+ org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), d3, org.bukkit.FluidCollisionMode.NEVER, false, 0.0, entity -> { // Paper - Call interact event; change raySize from 0.1 to 0.0 ++ org.bukkit.util.RayTraceResult result = this.player.level().getWorld().rayTrace(origin, origin.getDirection(), maxRange, org.bukkit.FluidCollisionMode.NEVER, false, 0.0, entity -> { // Paper - Call interact event; change raySize from 0.1 to 0.0 + Entity handle = ((CraftEntity) entity).getHandle(); + return entity != this.player.getBukkitEntity() && this.player.getBukkitEntity().canSee(entity) && !handle.isSpectator() && handle.isPickable() && !handle.isPassengerOfSameVehicle(this.player); + }); @@ -1741,8 +1727,8 @@ this.player.swing(packet.getHand()); } -@@ -1646,6 +_,21 @@ - public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { +@@ -1702,6 +_,21 @@ + public void handlePlayerCommand(final ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (this.hasClientLoaded()) { + // CraftBukkit start @@ -1763,13 +1749,13 @@ this.player.resetLastActionTime(); switch (packet.getAction()) { case START_SPRINTING: -@@ -1690,6 +_,14 @@ +@@ -1746,6 +_,14 @@ } - public void sendPlayerChatMessage(PlayerChatMessage chatMessage, ChatType.Bound boundChatType) { + public void sendPlayerChatMessage(final PlayerChatMessage message, final ChatType.Bound chatType) { + // CraftBukkit start - SPIGOT-7262: if hidden we have to send as disguised message. Query whether we should send at all (but changing this may not be expected). -+ if (!this.getCraftPlayer().canSeePlayer(chatMessage.link().sender())) { -+ this.sendDisguisedChatMessage(chatMessage.decoratedContent(), boundChatType); ++ if (!this.getCraftPlayer().canSeePlayer(message.link().sender())) { ++ this.sendDisguisedChatMessage(message.decoratedContent(), chatType); + return; + } + // CraftBukkit end @@ -1778,10 +1764,10 @@ this.send( new ClientboundPlayerChatPacket( this.nextChatIndex++, -@@ -1712,9 +_,11 @@ +@@ -1768,9 +_,11 @@ } - if (i > 4096) { + if (trackedCount > 4096) { - this.disconnect(Component.translatable("multiplayer.disconnect.too_many_pending_chats")); + this.disconnectAsync(Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause & add proper async disconnect } @@ -1790,8 +1776,8 @@ + // Paper end - Ensure that client receives chat packets in the same order that we add into the message signature cache } - public void sendDisguisedChatMessage(Component message, ChatType.Bound boundChatType) { -@@ -1725,6 +_,17 @@ + public void sendDisguisedChatMessage(final Component content, final ChatType.Bound chatType) { +@@ -1781,6 +_,17 @@ return this.connection.getRemoteAddress(); } @@ -1809,14 +1795,14 @@ public void switchToConfig() { this.waitingForSwitchToConfig = true; this.removePlayerFromWorld(); -@@ -1740,9 +_,16 @@ +@@ -1796,20 +_,27 @@ @Override - public void handleInteract(ServerboundInteractPacket packet) { + public void handleAttack(final ServerboundAttackPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit if (this.hasClientLoaded()) { - final ServerLevel serverLevel = this.player.level(); - final Entity target = packet.getTarget(serverLevel); + ServerLevel level = this.player.level(); + Entity target = level.getEntityOrPart(packet.entityId()); + // Spigot start + if (target == this.player && !this.player.isSpectator()) { + this.disconnect(Component.literal("Cannot interact with self!"), org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION); // Paper - kick event cause @@ -1824,147 +1810,134 @@ + } + // Spigot end this.player.resetLastActionTime(); - this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); - if (target != null) { -@@ -1751,16 +_,63 @@ + if (target != null && level.getWorldBorder().isWithinBounds(target.blockPosition())) { + AABB targetBounds = target.getBoundingBox(); + ItemStack mainHandItem = this.player.getMainHandItem(); +- if (this.player.isWithinAttackRange(mainHandItem, targetBounds, 3.0)) { ++ if (this.player.isWithinAttackRange(mainHandItem, targetBounds, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience + if (!mainHandItem.has(DataComponents.PIERCING_WEAPON)) { + if (target instanceof ItemEntity + || target instanceof ExperienceOrb + || target == this.player + || target instanceof AbstractArrow abstractArrow && !abstractArrow.isAttackable()) { +- this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked")); ++ this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - add cause + LOGGER.warn("Player {} tried to attack an invalid entity", this.player.getPlainTextName()); + } else if (mainHandItem.isItemEnabled(level.enabledFeatures())) { + if (!this.player.cannotAttackWithItem(mainHandItem, 5)) { +@@ -1819,25 +_,88 @@ + } } + } ++ // Paper start - PlayerUseUnknownEntityEvent ++ else if (target == null) { ++ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet.entityId(), true, net.minecraft.world.InteractionHand.MAIN_HAND, null); ++ } ++ // Paper end - PlayerUseUnknownEntityEvent ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes. + } + } - AABB boundingBox = target.getBoundingBox(); -- if (packet.isWithinRange(this.player, boundingBox, 3.0)) { -+ if (packet.isWithinRange(this.player, boundingBox, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience value for interact range - packet.dispatch( - new ServerboundInteractPacket.Handler() { -- private void performInteraction(InteractionHand hand, ServerGamePacketListenerImpl.EntityInteraction entityInteraction) { -+ private void performInteraction(InteractionHand hand, ServerGamePacketListenerImpl.EntityInteraction entityInteraction, PlayerInteractEntityEvent event) { // CraftBukkit - ItemStack itemInHand = ServerGamePacketListenerImpl.this.player.getItemInHand(hand); - if (itemInHand.isItemEnabled(serverLevel.enabledFeatures())) { - ItemStack itemStack = itemInHand.copy(); -- if (entityInteraction.run(ServerGamePacketListenerImpl.this.player, target, hand) instanceof InteractionResult.Success success -- ) -- { -+ // CraftBukkit start -+ final Item itemType = itemInHand.getItem(); -+ boolean triggerLeashUpdate = itemStack.is(Items.LEAD) && target instanceof net.minecraft.world.entity.Leashable; -+ -+ ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); -+ final boolean resendData = event.isCancelled() || !ServerGamePacketListenerImpl.this.player.getItemInHand(hand).is(itemType); -+ -+ // Entity in bucket - SPIGOT-4048 and SPIGOT-6859 -+ if (itemType == Items.WATER_BUCKET && target instanceof net.minecraft.world.entity.animal.Bucketable && target instanceof LivingEntity && resendData) { -+ target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it -+ } + @Override + public void handleInteract(final ServerboundInteractPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); ++ if (this.player.isImmobile()) return; // CraftBukkit + if (this.hasClientLoaded()) { + ServerLevel level = this.player.level(); + Entity target = level.getEntityOrPart(packet.entityId()); ++ // Spigot start ++ if (target == this.player && !this.player.isSpectator()) { ++ this.disconnect(Component.literal("Cannot interact with self!"), org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION); // Paper - kick event cause ++ return; ++ } ++ // Spigot end + this.player.resetLastActionTime(); + this.player.setShiftKeyDown(packet.usingSecondaryAction()); + if (target != null && level.getWorldBorder().isWithinBounds(target.blockPosition())) { + AABB targetBounds = target.getBoundingBox(); +- if (this.player.isWithinEntityInteractionRange(targetBounds, 3.0)) { ++ if (this.player.isWithinEntityInteractionRange(targetBounds, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience value for interact range + InteractionHand hand = packet.hand(); + Vec3 location = packet.location(); + ItemStack tool = this.player.getItemInHand(hand); + if (tool.isItemEnabled(level.enabledFeatures())) { + ItemStack usedItemStack = tool.copy(); ++ // CraftBukkit start ++ final Item itemType = tool.getItem(); ++ boolean triggerLeashUpdate = usedItemStack.is(Items.LEAD) && target instanceof net.minecraft.world.entity.Leashable; ++ ++ final PlayerInteractAtEntityEvent event = new PlayerInteractAtEntityEvent( ++ ServerGamePacketListenerImpl.this.getCraftPlayer(), target.getBukkitEntity(), ++ org.bukkit.craftbukkit.util.CraftVector.toBukkit(location), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) ++ ); ++ ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); ++ final boolean resendData = event.isCancelled() || !ServerGamePacketListenerImpl.this.player.getItemInHand(hand).is(itemType); ++ ++ // Entity in bucket - SPIGOT-4048 and SPIGOT-6859 ++ if (itemType == Items.WATER_BUCKET && target instanceof net.minecraft.world.entity.animal.Bucketable && target instanceof LivingEntity && resendData) { ++ target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it ++ } + -+ // Paper start - Fix inventory desync -+ if (resendData) { -+ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(ServerGamePacketListenerImpl.this.player, target, itemInHand)) { -+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); -+ } else { -+ ServerGamePacketListenerImpl.this.player.containerMenu.forceHeldSlot(hand); -+ } -+ } -+ // Paper end - Fix inventory desync ++ // Paper start - Fix inventory desync ++ if (resendData) { ++ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(ServerGamePacketListenerImpl.this.player, target, tool)) { ++ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); ++ } else { ++ ServerGamePacketListenerImpl.this.player.containerMenu.forceHeldSlot(hand); ++ } ++ } ++ // Paper end - Fix inventory desync + -+ if (triggerLeashUpdate && resendData) { -+ // Refresh the current leash state -+ ServerGamePacketListenerImpl.this.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(target, ((net.minecraft.world.entity.Leashable) target).getLeashHolder())); -+ } ++ if (triggerLeashUpdate && resendData) { ++ // Refresh the current leash state ++ ServerGamePacketListenerImpl.this.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(target, ((net.minecraft.world.entity.Leashable) target).getLeashHolder())); ++ } + -+ if (resendData) { -+ // Refresh the current entity metadata -+ target.refreshEntityData(ServerGamePacketListenerImpl.this.player); -+ // SPIGOT-7136 - Allays -+ if (target instanceof net.minecraft.world.entity.animal.allay.Allay || target instanceof net.minecraft.world.entity.animal.equine.AbstractHorse) { // Paper - Fix horse armor desync -+ ServerGamePacketListenerImpl.this.send(new net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket( -+ target.getId(), java.util.Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()) -+ .map((slot) -> com.mojang.datafixers.util.Pair.of(slot, ((LivingEntity) target).getItemBySlot(slot).copy())) -+ .collect(Collectors.toList()), true)); // Paper - sanitize -+ player.containerMenu.sendAllDataToRemote(); -+ } else { -+ ServerGamePacketListenerImpl.this.player.containerMenu.forceHeldSlot(hand); // Paper - fix slot desync (is this needed?) -+ } -+ } ++ if (resendData) { ++ // Refresh the current entity metadata ++ target.refreshEntityData(ServerGamePacketListenerImpl.this.player); ++ // SPIGOT-7136 - Allays ++ if (target instanceof net.minecraft.world.entity.animal.allay.Allay || target instanceof net.minecraft.world.entity.animal.equine.AbstractHorse) { // Paper - Fix horse armor desync ++ ServerGamePacketListenerImpl.this.send(new net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket( ++ target.getId(), java.util.Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()) ++ .map((slot) -> com.mojang.datafixers.util.Pair.of(slot, ((LivingEntity) target).getItemBySlot(slot).copy())) ++ .collect(Collectors.toList()), true)); // Paper - sanitize ++ player.containerMenu.sendAllDataToRemote(); ++ } else { ++ ServerGamePacketListenerImpl.this.player.containerMenu.forceHeldSlot(hand); // Paper - fix slot desync (is this needed?) ++ } ++ } + -+ if (event.isCancelled()) { -+ return; -+ } -+ // CraftBukkit end -+ InteractionResult result = entityInteraction.run(ServerGamePacketListenerImpl.this.player, target, hand); -+ -+ if (result instanceof InteractionResult.Success success // CraftBukkit -+ ) { - ItemStack itemStack1 = success.wasItemInteraction() ? itemStack : ItemStack.EMPTY; - CriteriaTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(ServerGamePacketListenerImpl.this.player, itemStack1, target); - if (success.swingSource() == InteractionResult.SwingSource.SERVER) { -@@ -1772,13 +_,13 @@ - - @Override - public void onInteraction(InteractionHand hand) { -- this.performInteraction(hand, Player::interactOn); -+ this.performInteraction(hand, Player::interactOn, new PlayerInteractEntityEvent(ServerGamePacketListenerImpl.this.getCraftPlayer(), target.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand))); // CraftBukkit - } - - @Override - public void onInteraction(InteractionHand hand, Vec3 interactionLocation) { - this.performInteraction( -- hand, (player, entity, interactionHand) -> entity.interactAt(player, interactionLocation, interactionHand) -+ hand, (player, entity, interactionHand) -> entity.interactAt(player, interactionLocation, interactionHand), new PlayerInteractAtEntityEvent(ServerGamePacketListenerImpl.this.getCraftPlayer(), target.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(interactionLocation), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)) // CraftBukkit - ); - } - -@@ -1786,16 +_,22 @@ - public void onAttack() { - if (!(target instanceof ItemEntity) - && !(target instanceof ExperienceOrb) -- && target != ServerGamePacketListenerImpl.this.player -+ && (target != ServerGamePacketListenerImpl.this.player || ServerGamePacketListenerImpl.this.player.isSpectator()) // CraftBukkit - && !(target instanceof AbstractArrow abstractArrow && !abstractArrow.isAttackable())) { - ItemStack itemInHand = ServerGamePacketListenerImpl.this.player.getItemInHand(InteractionHand.MAIN_HAND); - if (itemInHand.isItemEnabled(serverLevel.enabledFeatures())) { - if (!ServerGamePacketListenerImpl.this.player.cannotAttackWithItem(itemInHand, 5)) { -+ // Paper start - redirect attacks with piercing weapon -+ PiercingWeapon piercingWeapon = itemInHand.get(DataComponents.PIERCING_WEAPON); -+ if (piercingWeapon != null) { -+ piercingWeapon.attack(ServerGamePacketListenerImpl.this.player, EquipmentSlot.MAINHAND); -+ } else -+ // Paper end - redirect attacks with piercing weapon - ServerGamePacketListenerImpl.this.player.attack(target); - } - } - } else { -- ServerGamePacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked")); -+ ServerGamePacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - add cause - ServerGamePacketListenerImpl.LOGGER - .warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getPlainTextName()); - } -@@ -1804,6 +_,27 @@ - ); ++ if (event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + if (this.player.interactOn(target, hand, location) instanceof InteractionResult.Success success) { + ItemStack awardedForStack = success.wasItemInteraction() ? usedItemStack : ItemStack.EMPTY; + CriteriaTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(this.player, awardedForStack, target); +@@ -1848,6 +_,12 @@ + } } } + // Paper start - PlayerUseUnknownEntityEvent -+ else { -+ packet.dispatch(new net.minecraft.network.protocol.game.ServerboundInteractPacket.Handler() { -+ @Override -+ public void onInteraction(net.minecraft.world.InteractionHand hand) { -+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, hand, null); -+ } -+ -+ @Override -+ public void onInteraction(net.minecraft.world.InteractionHand hand, net.minecraft.world.phys.Vec3 pos) { -+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, hand, pos); -+ } -+ -+ @Override -+ public void onAttack() { -+ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet, net.minecraft.world.InteractionHand.MAIN_HAND, null); -+ } -+ }); ++ else if (target == null) { ++ CraftEventFactory.callPlayerUseUnknownEntityEvent(ServerGamePacketListenerImpl.this.player, packet.entityId(), false, packet.hand(), packet.location()); + } + // Paper end - PlayerUseUnknownEntityEvent + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes. } } -@@ -1816,7 +_,7 @@ +@@ -1859,7 +_,7 @@ + ServerLevel level = this.player.level(); + Entity target = level.getEntityOrPart(packet.entityId()); + if (target != null && level.getWorldBorder().isWithinBounds(target.blockPosition())) { +- if (this.player.isWithinEntityInteractionRange(target.getBoundingBox(), 3.0)) { ++ if (this.player.isWithinEntityInteractionRange(target.getBoundingBox(), io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience + if (target.isPickable()) { + this.player.setCamera(target); + } +@@ -1877,7 +_,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1973,7 +1946,7 @@ this.resetPosition(); this.restartClientLoadTimerAfterRespawn(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); -@@ -1825,12 +_,12 @@ +@@ -1886,12 +_,12 @@ return; } @@ -1989,10 +1962,19 @@ } } break; -@@ -1841,16 +_,27 @@ +@@ -1904,7 +_,7 @@ + } + + private void sendGameRuleValues() { +- if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER)) { ++ if (!this.player.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER) && !this.player.getBukkitEntity().hasPermission("minecraft.command.gamerule")) { // Paper - add permission check + LOGGER.warn("Player {} tried to request game rule values without required permissions", this.player.getGameProfile().name()); + } else { + GameRules gameRules = this.player.level().getGameRules(); +@@ -1920,16 +_,27 @@ @Override - public void handleContainerClose(ServerboundContainerClosePacket packet) { + public void handleContainerClose(final ServerboundContainerClosePacket packet) { + // Paper start - Inventory close reason + this.handleContainerClose(packet, org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLAYER); + } @@ -2007,7 +1989,7 @@ } @Override - public void handleContainerClick(ServerboundContainerClickPacket packet) { + public void handleContainerClick(final ServerboundContainerClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit this.player.resetLastActionTime(); @@ -2019,24 +2001,24 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1866,7 +_,298 @@ +@@ -1945,7 +_,298 @@ } else { - boolean flag = packet.stateId() != this.player.containerMenu.getStateId(); + boolean fullResyncNeeded = packet.stateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); -- this.player.containerMenu.clicked(slotNum, packet.buttonNum(), packet.clickType(), this.player); +- this.player.containerMenu.clicked(slotIndex, packet.buttonNum(), packet.containerInput(), this.player); + // CraftBukkit start - Call InventoryClickEvent -+ if (slotNum < -1 && slotNum != net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE) { ++ if (slotIndex < -1 && slotIndex != net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE) { + return; + } + + org.bukkit.inventory.InventoryView inventory = this.player.containerMenu.getBukkitView(); -+ SlotType type = inventory.getSlotType(slotNum); ++ SlotType type = inventory.getSlotType(slotIndex); + + InventoryClickEvent event; + ClickType click = ClickType.UNKNOWN; + InventoryAction action = InventoryAction.UNKNOWN; + -+ switch (packet.clickType()) { ++ switch (packet.containerInput()) { + case PICKUP: + if (packet.buttonNum() == 0) { + click = ClickType.LEFT; @@ -2045,14 +2027,14 @@ + } + if (packet.buttonNum() == 0 || packet.buttonNum() == 1) { + action = InventoryAction.NOTHING; // Don't want to repeat ourselves -+ if (slotNum == net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE) { ++ if (slotIndex == net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE) { + if (!this.player.containerMenu.getCarried().isEmpty()) { + action = packet.buttonNum() == 0 ? InventoryAction.DROP_ALL_CURSOR : InventoryAction.DROP_ONE_CURSOR; + } -+ } else if (slotNum < 0) { ++ } else if (slotIndex < 0) { + action = InventoryAction.NOTHING; + } else { -+ Slot slot = this.player.containerMenu.getSlot(slotNum); ++ Slot slot = this.player.containerMenu.getSlot(slotIndex); + if (slot != null) { + ItemStack clickedItem = slot.getItem(); + ItemStack cursor = this.player.containerMenu.getCarried(); @@ -2129,10 +2111,10 @@ + click = ClickType.SHIFT_RIGHT; + } + if (packet.buttonNum() == 0 || packet.buttonNum() == 1) { -+ if (slotNum < 0) { ++ if (slotIndex < 0) { + action = InventoryAction.NOTHING; + } else { -+ Slot slot = this.player.containerMenu.getSlot(slotNum); ++ Slot slot = this.player.containerMenu.getSlot(slotIndex); + if (slot != null && slot.mayPickup(this.player) && slot.hasItem()) { + action = InventoryAction.MOVE_TO_OTHER_INVENTORY; + } else { @@ -2144,13 +2126,13 @@ + case SWAP: + if ((packet.buttonNum() >= 0 && packet.buttonNum() < 9) || packet.buttonNum() == Inventory.SLOT_OFFHAND) { + // Paper start - Add slot sanity checks to container clicks -+ if (slotNum < 0) { ++ if (slotIndex < 0) { + action = InventoryAction.NOTHING; + break; + } + // Paper end - Add slot sanity checks to container clicks + click = (packet.buttonNum() == Inventory.SLOT_OFFHAND) ? ClickType.SWAP_OFFHAND : ClickType.NUMBER_KEY; -+ Slot clickedSlot = this.player.containerMenu.getSlot(slotNum); ++ Slot clickedSlot = this.player.containerMenu.getSlot(slotIndex); + if (clickedSlot.mayPickup(this.player)) { + ItemStack hotbar = this.player.getInventory().getItem(packet.buttonNum()); + if ((!hotbar.isEmpty() && clickedSlot.mayPlace(hotbar)) || (hotbar.isEmpty() && clickedSlot.hasItem())) { // Paper - modernify this logic (no such thing as a "hotbar move and readd" @@ -2166,10 +2148,10 @@ + case CLONE: + if (packet.buttonNum() == 2) { + click = ClickType.MIDDLE; -+ if (slotNum < 0) { ++ if (slotIndex < 0) { + action = InventoryAction.NOTHING; + } else { -+ Slot slot = this.player.containerMenu.getSlot(slotNum); ++ Slot slot = this.player.containerMenu.getSlot(slotIndex); + if (slot != null && slot.hasItem() && this.player.getAbilities().instabuild && this.player.containerMenu.getCarried().isEmpty()) { + action = InventoryAction.CLONE_STACK; + } else { @@ -2182,10 +2164,10 @@ + } + break; + case THROW: -+ if (slotNum >= 0) { ++ if (slotIndex >= 0) { + if (packet.buttonNum() == 0) { + click = ClickType.DROP; -+ Slot slot = this.player.containerMenu.getSlot(slotNum); ++ Slot slot = this.player.containerMenu.getSlot(slotIndex); + if (slot != null && slot.hasItem() && slot.mayPickup(this.player) && !slot.getItem().isEmpty() && slot.getItem().getItem() != Items.AIR) { + action = InventoryAction.DROP_ONE_SLOT; + } else { @@ -2193,7 +2175,7 @@ + } + } else if (packet.buttonNum() == 1) { + click = ClickType.CONTROL_DROP; -+ Slot slot = this.player.containerMenu.getSlot(slotNum); ++ Slot slot = this.player.containerMenu.getSlot(slotIndex); + if (slot != null && slot.hasItem() && slot.mayPickup(this.player) && !slot.getItem().isEmpty() && slot.getItem().getItem() != Items.AIR) { + action = InventoryAction.DROP_ALL_SLOT; + } else { @@ -2223,18 +2205,18 @@ + if (this.player.containerMenu.quickcraftSlots.size() == 1) { + int index = containerMenu.quickcraftSlots.iterator().next().index; + containerMenu.resetQuickCraft(); -+ this.handleContainerClick(new ServerboundContainerClickPacket(packet.containerId(), packet.stateId(), (short) index, (byte) containerMenu.quickcraftType, net.minecraft.world.inventory.ClickType.PICKUP, packet.changedSlots(), packet.carriedItem())); ++ this.handleContainerClick(new ServerboundContainerClickPacket(packet.containerId(), packet.stateId(), (short) index, (byte) containerMenu.quickcraftType, net.minecraft.world.inventory.ContainerInput.PICKUP, packet.changedSlots(), packet.carriedItem())); + return; + } + } + } + // Paper end - Fix CraftBukkit drag system -+ this.player.containerMenu.clicked(slotNum, packet.buttonNum(), packet.clickType(), this.player); ++ this.player.containerMenu.clicked(slotIndex, packet.buttonNum(), packet.containerInput(), this.player); + break; + case PICKUP_ALL: + click = ClickType.DOUBLE_CLICK; + action = InventoryAction.NOTHING; -+ if (slotNum >= 0 && !this.player.containerMenu.getCarried().isEmpty()) { ++ if (slotIndex >= 0 && !this.player.containerMenu.getCarried().isEmpty()) { + ItemStack cursor = this.player.containerMenu.getCarried(); + action = InventoryAction.NOTHING; + // Quick check for if we have any of the item @@ -2247,7 +2229,7 @@ + break; + } + -+ if (packet.clickType() != net.minecraft.world.inventory.ClickType.QUICK_CRAFT) { ++ if (packet.containerInput() != net.minecraft.world.inventory.ContainerInput.QUICK_CRAFT) { + // If a non quick craft packet is emitted by the client while in quick crafting, the server will reset quick crafting and + // discard any further packet action. + if (this.player.containerMenu.quickcraftStatus != 0) { @@ -2255,42 +2237,42 @@ + } + + if (click == ClickType.NUMBER_KEY) { -+ event = new InventoryClickEvent(inventory, type, slotNum, click, action, packet.buttonNum()); ++ event = new InventoryClickEvent(inventory, type, slotIndex, click, action, packet.buttonNum()); + } else { -+ event = new InventoryClickEvent(inventory, type, slotNum, click, action); ++ event = new InventoryClickEvent(inventory, type, slotIndex, click, action); + } + + org.bukkit.inventory.Inventory top = inventory.getTopInventory(); -+ if (slotNum == 0 && top instanceof final org.bukkit.inventory.CraftingInventory craftingInv) { ++ if (slotIndex == 0 && top instanceof final org.bukkit.inventory.CraftingInventory craftingInv) { + org.bukkit.inventory.Recipe recipe = craftingInv.getRecipe(); + if (recipe != null) { + if (click == ClickType.NUMBER_KEY) { -+ event = new CraftItemEvent(recipe, inventory, type, slotNum, click, action, packet.buttonNum()); ++ event = new CraftItemEvent(recipe, inventory, type, slotIndex, click, action, packet.buttonNum()); + } else { -+ event = new CraftItemEvent(recipe, inventory, type, slotNum, click, action); ++ event = new CraftItemEvent(recipe, inventory, type, slotIndex, click, action); + } + } + } + -+ if (slotNum == 3 && top instanceof final org.bukkit.inventory.SmithingInventory smithingInv) { ++ if (slotIndex == 3 && top instanceof final org.bukkit.inventory.SmithingInventory smithingInv) { + org.bukkit.inventory.ItemStack result = smithingInv.getResult(); + if (result != null) { + if (click == ClickType.NUMBER_KEY) { -+ event = new SmithItemEvent(inventory, type, slotNum, click, action, packet.buttonNum()); ++ event = new SmithItemEvent(inventory, type, slotIndex, click, action, packet.buttonNum()); + } else { -+ event = new SmithItemEvent(inventory, type, slotNum, click, action); ++ event = new SmithItemEvent(inventory, type, slotIndex, click, action); + } + } + } + + // Paper start - cartography item event -+ if (slotNum == net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT && top instanceof org.bukkit.inventory.CartographyInventory cartographyInventory) { ++ if (slotIndex == net.minecraft.world.inventory.CartographyTableMenu.RESULT_SLOT && top instanceof org.bukkit.inventory.CartographyInventory cartographyInventory) { + org.bukkit.inventory.ItemStack result = cartographyInventory.getResult(); + if (result != null && !result.isEmpty()) { + if (click == ClickType.NUMBER_KEY) { -+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, slotNum, click, action, packet.buttonNum()); ++ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, slotIndex, click, action, packet.buttonNum()); + } else { -+ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, slotNum, click, action); ++ event = new io.papermc.paper.event.player.CartographyItemEvent(inventory, type, slotIndex, click, action); + } + } + } @@ -2306,7 +2288,7 @@ + } + + if (event.getResult() != org.bukkit.event.Event.Result.DENY) { // if denied, synchronizing is fully handled by broadcastChanges at the end -+ this.player.containerMenu.clicked(slotNum, packet.buttonNum(), packet.clickType(), this.player); ++ this.player.containerMenu.clicked(slotIndex, packet.buttonNum(), packet.containerInput(), this.player); + } + + if (event instanceof CraftItemEvent || event instanceof SmithItemEvent) { @@ -2317,9 +2299,9 @@ + } + // CraftBukkit end - for (Entry entry : Int2ObjectMaps.fastIterable(packet.changedSlots())) { - this.player.containerMenu.setRemoteSlotUnsafe(entry.getIntKey(), entry.getValue()); -@@ -1879,6 +_,8 @@ + for (Entry e : Int2ObjectMaps.fastIterable(packet.changedSlots())) { + this.player.containerMenu.setRemoteSlotUnsafe(e.getIntKey(), e.getValue()); +@@ -1958,6 +_,8 @@ } else { this.player.containerMenu.broadcastChanges(); } @@ -2328,10 +2310,10 @@ } } } -@@ -1886,6 +_,14 @@ +@@ -1965,6 +_,14 @@ @Override - public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { + public void handlePlaceRecipe(final ServerboundPlaceRecipePacket packet) { + // Paper start - auto recipe limit + if (!org.bukkit.Bukkit.isPrimaryThread()) { + if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) { @@ -2343,12 +2325,12 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); this.player.resetLastActionTime(); if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) { -@@ -1902,9 +_,44 @@ +@@ -1981,9 +_,44 @@ return; } + // Paper start - Add PlayerRecipeBookClickEvent -+ NamespacedKey recipeName = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipeHolder.id().identifier()); ++ NamespacedKey recipeName = org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipe.id().identifier()); + boolean makeAll = packet.useMaxItems(); + com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent( + this.player.getBukkitEntity(), recipeName, makeAll @@ -2361,12 +2343,12 @@ + if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) { + // Paper end - Add PlayerRecipeBookClickEvent + // CraftBukkit start - implement PlayerRecipeBookClickEvent -+ org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(recipeName); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event -+ if (recipe == null) { ++ org.bukkit.inventory.Recipe bukkitRecipe = this.cserver.getRecipe(recipeName); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event ++ if (bukkitRecipe == null) { + return; + } + // Paper start - Add PlayerRecipeBookClickEvent - forward to legacy event -+ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll); ++ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, bukkitRecipe, makeAll); + recipeName = ((org.bukkit.Keyed) event.getRecipe()).getKey(); + makeAll = event.isShiftClick(); + } @@ -2376,46 +2358,46 @@ + // Paper end - Add PlayerRecipeBookClickEvent - forward to legacy event + + // Cast to keyed should be safe as the recipe will never be a MerchantRecipe. -+ recipeHolder = this.server.getRecipeManager().byKey(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.RECIPE, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(recipeName))).orElse(null); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event -+ if (recipeHolder == null) { ++ recipe = this.server.getRecipeManager().byKey(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.RECIPE, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(recipeName))).orElse(null); // Paper - Add PlayerRecipeBookClickEvent - forward to legacy event ++ if (recipe == null) { + return; + } + RecipeBookMenu.PostPlaceAction postPlaceAction = recipeBookMenu.handlePlacement( -- packet.useMaxItems(), this.player.isCreative(), recipeHolder, this.player.level(), this.player.getInventory() -+ makeAll, this.player.isCreative(), recipeHolder, this.player.level(), this.player.getInventory() +- packet.useMaxItems(), this.player.isCreative(), recipe, this.player.level(), this.player.getInventory() ++ makeAll, this.player.isCreative(), recipe, this.player.level(), this.player.getInventory() ); + // CraftBukkit end if (postPlaceAction == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { - this.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, recipeFromDisplay.display().display())); + this.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, displayInfo.display().display())); } -@@ -1918,6 +_,7 @@ +@@ -1997,6 +_,7 @@ @Override - public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { + public void handleContainerButtonClick(final ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + if (this.player.isImmobile()) return; // CraftBukkit this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1927,6 +_,7 @@ - if (flag) { +@@ -2006,6 +_,7 @@ + if (clickAccepted) { this.player.containerMenu.broadcastChanges(); } + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes. } } } -@@ -1943,10 +_,48 @@ +@@ -2022,10 +_,48 @@ - boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; - boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize(); -+ if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot + boolean validSlot = packet.slotNum() >= 1 && packet.slotNum() <= 45; + boolean validData = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize(); ++ if (drop || (validSlot && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot + // CraftBukkit start - Call click event + org.bukkit.inventory.InventoryView inventory = this.player.inventoryMenu.getBukkitView(); + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packet.itemStack()); + + SlotType type = SlotType.QUICKBAR; -+ if (flag) { ++ if (drop) { + type = SlotType.OUTSIDE; + } else if (packet.slotNum() < 36) { + if (packet.slotNum() >= 5 && packet.slotNum() < 9) { @@ -2424,7 +2406,7 @@ + type = SlotType.CONTAINER; + } + } -+ InventoryCreativeEvent event = new InventoryCreativeEvent(inventory, type, flag ? net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE : packet.slotNum(), item); ++ InventoryCreativeEvent event = new InventoryCreativeEvent(inventory, type, drop ? net.minecraft.world.inventory.AbstractContainerMenu.SLOT_CLICKED_OUTSIDE : packet.slotNum(), item); + this.cserver.getPluginManager().callEvent(event); + + itemStack = CraftItemStack.asNMSCopy(event.getCursor()); @@ -2432,7 +2414,7 @@ + switch (event.getResult()) { + case ALLOW: + // Plugin cleared the id / stacksize checks -+ flag2 = true; ++ validData = true; + break; + case DEFAULT: + break; @@ -2446,57 +2428,57 @@ + } + } + // CraftBukkit end - if (flag1 && flag2) { + if (validSlot && validData) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack); this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack); this.player.inventoryMenu.broadcastChanges(); + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes. - } else if (flag && flag2) { + } else if (drop && validData) { if (this.dropSpamThrottler.isUnderThreshold()) { this.dropSpamThrottler.increment(); -@@ -1960,15 +_,38 @@ +@@ -2039,15 +_,38 @@ @Override - public void handleSignUpdate(ServerboundSignUpdatePacket packet) { -- List list = Stream.of(packet.getLines()).map(ChatFormatting::stripFormatting).collect(Collectors.toList()); + public void handleSignUpdate(final ServerboundSignUpdatePacket packet) { +- List lines = Stream.of(packet.getLines()).map(ChatFormatting::stripFormatting).collect(Collectors.toList()); + // Paper start - Limit client sign length -+ String[] lines = packet.getLines(); -+ for (int i = 0; i < lines.length; ++i) { -+ if (MAX_SIGN_LINE_LENGTH > 0 && lines[i].length() > MAX_SIGN_LINE_LENGTH) { ++ String[] linesArray = packet.getLines(); ++ for (int i = 0; i < linesArray.length; ++i) { ++ if (MAX_SIGN_LINE_LENGTH > 0 && linesArray[i].length() > MAX_SIGN_LINE_LENGTH) { + // This handles multibyte characters as 1 -+ int offset = lines[i].codePoints().limit(MAX_SIGN_LINE_LENGTH).map(Character::charCount).sum(); -+ if (offset < lines[i].length()) { -+ lines[i] = lines[i].substring(0, offset); // this will break any filtering, but filtering is NYI as of 1.17 ++ int offset = linesArray[i].codePoints().limit(MAX_SIGN_LINE_LENGTH).map(Character::charCount).sum(); ++ if (offset < linesArray[i].length()) { ++ linesArray[i] = linesArray[i].substring(0, offset); // this will break any filtering, but filtering is NYI as of 1.17 + } + } + } -+ List list = Stream.of(lines).map(ChatFormatting::stripFormatting).collect(Collectors.toList()); ++ List lines = Stream.of(linesArray).map(ChatFormatting::stripFormatting).collect(Collectors.toList()); + // Paper end - Limit client sign length - this.filterTextPacket(list).thenAcceptAsync(texts -> this.updateSignText(packet, (List)texts), this.server); + this.filterTextPacket(lines).thenAcceptAsync(filteredLines -> this.updateSignText(packet, (List)filteredLines), this.server); } - private void updateSignText(ServerboundSignUpdatePacket packet, List filteredText) { + private void updateSignText(final ServerboundSignUpdatePacket packet, final List lines) { + if (this.player.isImmobile()) return; // CraftBukkit this.player.resetLastActionTime(); - ServerLevel serverLevel = this.player.level(); + ServerLevel level = this.player.level(); BlockPos pos = packet.getPos(); - if (serverLevel.hasChunkAt(pos)) { + if (level.hasChunkAt(pos)) { + // Paper start - Add API for client-side signs + if (!new io.papermc.paper.event.packet.UncheckedSignChangeEvent( + this.player.getBukkitEntity(), + io.papermc.paper.util.MCUtil.toPosition(pos), + packet.isFrontText() ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK, -+ filteredText.stream().map(line -> net.kyori.adventure.text.Component.text(line.raw())).toList()) ++ lines.stream().map(line -> net.kyori.adventure.text.Component.text(line.raw())).toList()) + .callEvent()) { + return; + } + // Paper end - Add API for client-side signs - if (!(serverLevel.getBlockEntity(pos) instanceof SignBlockEntity signBlockEntity)) { + if (!(level.getBlockEntity(pos) instanceof SignBlockEntity sign)) { return; } -@@ -1980,14 +_,32 @@ +@@ -2059,14 +_,32 @@ @Override - public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { + public void handlePlayerAbilities(final ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); - this.player.getAbilities().flying = packet.isFlying() && this.player.getAbilities().mayfly; + // CraftBukkit start @@ -2513,7 +2495,7 @@ } @Override - public void handleClientInformation(ServerboundClientInformationPacket packet) { + public void handleClientInformation(final ServerboundClientInformationPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + // Paper start - do not accept invalid information + if (packet.information().viewDistance() < 0) { @@ -2522,13 +2504,13 @@ + return; + } + // Paper end - do not accept invalid information - boolean isModelPartShown = this.player.isModelPartShown(PlayerModelPart.HAT); + boolean wasHatShown = this.player.isModelPartShown(PlayerModelPart.HAT); this.player.updateOptions(packet.information()); + this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper - if (this.player.isModelPartShown(PlayerModelPart.HAT) != isModelPartShown) { + if (this.player.isModelPartShown(PlayerModelPart.HAT) != wasHatShown) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } -@@ -2003,7 +_,7 @@ +@@ -2082,7 +_,7 @@ packet.difficulty().getDisplayName() ); } else { @@ -2537,7 +2519,7 @@ } } -@@ -2017,7 +_,7 @@ +@@ -2096,7 +_,7 @@ packet.mode().getShortDisplayName().getString() ); } else { @@ -2546,18 +2528,18 @@ } } -@@ -2037,7 +_,7 @@ - ProfilePublicKey.Data data2 = data.profilePublicKey(); - if (!Objects.equals(data1, data2)) { - if (data1 != null && data2.expiresAt().isBefore(data1.expiresAt())) { +@@ -2116,7 +_,7 @@ + ProfilePublicKey.Data newProfileKey = newChatSession.profilePublicKey(); + if (!Objects.equals(oldProfileKey, newProfileKey)) { + if (oldProfileKey != null && newProfileKey.expiresAt().isBefore(oldProfileKey.expiresAt())) { - this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY); + this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes } else { try { - SignatureValidator signatureValidator = this.server.services().profileKeySignatureValidator(); -@@ -2048,8 +_,8 @@ + SignatureValidator profileKeySignatureValidator = this.server.services().profileKeySignatureValidator(); +@@ -2127,8 +_,8 @@ - this.resetPlayerChatState(data.validate(this.player.getGameProfile(), signatureValidator)); + this.resetPlayerChatState(newChatSession.validate(this.player.getGameProfile(), profileKeySignatureValidator)); } catch (ProfilePublicKey.ValidationException var6) { - LOGGER.error("Failed to validate profile key: {}", var6.getMessage()); - this.disconnect(var6.getComponent()); @@ -2566,7 +2548,7 @@ } } } -@@ -2060,11 +_,13 @@ +@@ -2139,11 +_,13 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -2581,16 +2563,16 @@ } } -@@ -2082,27 +_,32 @@ +@@ -2161,27 +_,32 @@ - private void resetPlayerChatState(RemoteChatSession chatSession) { + private void resetPlayerChatState(final RemoteChatSession chatSession) { this.chatSession = chatSession; + this.hasLoggedExpiry = false; // Paper - Prevent causing expired keys from impacting new joins this.signedMessageDecoder = chatSession.createMessageDecoder(this.player.getUUID()); this.chatMessageChain .append( () -> { -+ server.executeBlocking(() -> { // Paper - Broadcast chat session update sync ++ this.server.executeBlocking(() -> { // Paper - Broadcast chat session update sync this.player.setChatSession(chatSession); this.server .getPlayerList() @@ -2604,18 +2586,18 @@ } @Override - public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + public void handleCustomPayload(final ServerboundCustomPayloadPacket packet) { + super.handleCustomPayload(packet); // Paper } @Override - public void handleClientTickEnd(ServerboundClientTickEndPacket packet) { + public void handleClientTickEnd(final ServerboundClientTickEndPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); + this.tickEndEvent.callEvent(); // Paper - add client tick end event if (!this.receivedMovementThisTick) { this.player.setKnownMovement(Vec3.ZERO); } -@@ -2134,12 +_,23 @@ +@@ -2213,12 +_,23 @@ } public void tickClientLoadTimeout() { @@ -2641,9 +2623,9 @@ this.clientLoadedTimeoutTimer = 0; } -@@ -2156,4 +_,80 @@ - interface EntityInteraction { - InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand); +@@ -2230,4 +_,80 @@ + this.waitingForRespawn = false; + this.clientLoadedTimeoutTimer = 60; } + + // Paper start - Add fail move event diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java.patch index 54a47d3a4673..6d17de399e7b 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java.patch @@ -18,13 +18,13 @@ private final Connection connection; + - public ServerHandshakePacketListenerImpl(MinecraftServer server, Connection connection) { + public ServerHandshakePacketListenerImpl(final MinecraftServer server, final Connection connection) { this.server = server; this.connection = connection; @@ -24,6 +_,7 @@ @Override - public void handleIntention(ClientIntentionPacket packet) { + public void handleIntention(final ClientIntentionPacket packet) { + this.connection.hostname = packet.hostName() + ":" + packet.port(); // CraftBukkit - set hostname switch (packet.intention()) { case LOGIN: @@ -40,7 +40,8 @@ + // Paper end } - private void beginLogin(ClientIntentionPacket packet, boolean transferred) { +- private void beginLogin(final ClientIntentionPacket packet, final boolean transfer) { ++ private void beginLogin(ClientIntentionPacket packet, final boolean transfer) { // Paper - remove packet final this.connection.setupOutboundProtocol(LoginProtocols.CLIENTBOUND); + // Paper start - Connection throttle + try { @@ -74,22 +75,22 @@ + } + // Paper end - Connection throttle if (packet.protocolVersion() != SharedConstants.getCurrentVersion().protocolVersion()) { -- Component component; +- Component reason; - if (packet.protocolVersion() < 754) { -- component = Component.translatable("multiplayer.disconnect.outdated_client", SharedConstants.getCurrentVersion().name()); -+ net.kyori.adventure.text.Component adventureComponent; // Paper - Fix hex colors not working in some kick messages +- reason = Component.translatable("multiplayer.disconnect.outdated_client", SharedConstants.getCurrentVersion().name()); ++ net.kyori.adventure.text.Component adventureReason; // Paper - Fix hex colors not working in some kick messages + if (packet.protocolVersion() < SharedConstants.getCurrentVersion().protocolVersion()) { // Spigot - SPIGOT-7546: Handle version check correctly for outdated client message -+ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().name())); // Spigot // Paper - Fix hex colors not working in some kick messages ++ adventureReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().name())); // Spigot // Paper - Fix hex colors not working in some kick messages } else { -- component = Component.translatable("multiplayer.disconnect.incompatible", SharedConstants.getCurrentVersion().name()); -+ adventureComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().name())); // Spigot // Paper - Fix hex colors not working in some kick messages +- reason = Component.translatable("multiplayer.disconnect.incompatible", SharedConstants.getCurrentVersion().name()); ++ adventureReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(java.text.MessageFormat.format(org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getCurrentVersion().name())); // Spigot // Paper - Fix hex colors not working in some kick messages } -+ Component component = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureComponent); // Paper - Fix hex colors not working in some kick messages ++ Component reason = io.papermc.paper.adventure.PaperAdventure.asVanilla(adventureReason); // Paper - Fix hex colors not working in some kick messages - this.connection.send(new ClientboundLoginDisconnectPacket(component)); - this.connection.disconnect(component); + this.connection.send(new ClientboundLoginDisconnectPacket(reason)); + this.connection.disconnect(reason); } else { - this.connection.setupInboundProtocol(LoginProtocols.SERVERBOUND, new ServerLoginPacketListenerImpl(this.server, this.connection, transferred)); + this.connection.setupInboundProtocol(LoginProtocols.SERVERBOUND, new ServerLoginPacketListenerImpl(this.server, this.connection, transfer)); + // Paper start - PlayerHandshakeEvent + boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee; + boolean handledByEvent = false; diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch index f7a4161d565d..cc8a081147a0 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -12,16 +12,16 @@ + public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener { private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0); - static final Logger LOGGER = LogUtils.getLogger(); + private static final Logger LOGGER = LogUtils.getLogger(); + private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads private static final int MAX_TICKS_BEFORE_LOGIN = 600; private final byte[] challenge; - final MinecraftServer server; + private final MinecraftServer server; @@ -56,10 +_,15 @@ - final ServerActivityMonitor serverActivityMonitor; + private final ServerActivityMonitor serverActivityMonitor; public volatile ServerLoginPacketListenerImpl.State state = ServerLoginPacketListenerImpl.State.HELLO; private int tick; -- @Nullable String requestedUsername; +- private @Nullable String requestedUsername; + public @Nullable String requestedUsername; // Paper - public public @Nullable GameProfile authenticatedProfile; private final String serverId = ""; @@ -33,8 +33,8 @@ + private final io.papermc.paper.connection.PaperPlayerLoginConnection paperLoginConnection; // Paper - Config API + private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login - public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { - this.server = server; + public ServerLoginPacketListenerImpl(final MinecraftServer minecraftserver, final Connection connection, final boolean transferred) { + this.server = minecraftserver; @@ -67,10 +_,20 @@ this.serverActivityMonitor = this.server.getServerActivityMonitor(); this.challenge = Ints.toByteArray(RandomSource.create().nextInt()); @@ -81,16 +81,16 @@ public boolean isAcceptingMessages() { return this.connection.isConnected(); @@ -95,6 +_,7 @@ - LOGGER.info("Disconnecting {}: {}", this.getUserName(), reason.getString()); - this.connection.send(new ClientboundLoginDisconnectPacket(reason)); - this.connection.disconnect(reason); + LOGGER.info("Disconnecting {}: {}", this.getUserName(), component.getString()); + this.connection.send(new ClientboundLoginDisconnectPacket(component)); + this.connection.disconnect(component); + this.disconnecting = true; // Paper - Fix disconnect still ticking login } catch (Exception var3) { LOGGER.error("Error whilst disconnecting player", (Throwable)var3); } @@ -117,7 +_,14 @@ @Override - public void handleHello(ServerboundHelloPacket packet) { + public void handleHello(final ServerboundHelloPacket packet) { Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet"); - Validate.validState(StringUtil.isValidPlayerName(packet.name()), "Invalid characters in username"); + // Paper start - Validate usernames @@ -140,27 +140,27 @@ } @@ -139,7 +_,7 @@ - private void verifyLoginAndFinishConnectionSetup(GameProfile profile) { + private void verifyLoginAndFinishConnectionSetup(final GameProfile profile) { PlayerList playerList = this.server.getPlayerList(); -- Component component = playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile)); -+ Component component = org.bukkit.craftbukkit.event.CraftEventFactory.handleLoginResult(playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile)), this.paperLoginConnection, this.connection, profile, this.server, true); // Paper - if (component != null) { - this.disconnect(component); +- Component error = playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile)); ++ Component error = org.bukkit.craftbukkit.event.CraftEventFactory.handleLoginResult(playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile)), this.paperLoginConnection, this.connection, profile, this.server, true); // Paper + if (error != null) { + this.disconnect(error); } else { @@ -151,7 +_,7 @@ ); } -- boolean flag = playerList.disconnectAllPlayersWithProfile(profile.id()); -+ boolean flag = playerList.disconnectAllPlayersWithProfile(profile); // Paper - validate usernames - if (flag) { +- boolean waitForDisconnection = playerList.disconnectAllPlayersWithProfile(profile.id()); ++ boolean waitForDisconnection = playerList.disconnectAllPlayersWithProfile(profile); // Paper - validate usernames + if (waitForDisconnection) { this.state = ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT; } else { @@ -163,6 +_,7 @@ - private void finishLoginAndWaitForClient(GameProfile profile) { + private void finishLoginAndWaitForClient(final GameProfile gameProfile) { this.state = ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING; - this.connection.send(new ClientboundLoginFinishedPacket(profile)); -+ this.server.services().paper().filledProfileCache().add(profile); // Paper - update profile cache + this.connection.send(new ClientboundLoginFinishedPacket(gameProfile)); ++ this.server.services().paper().filledProfileCache().add(gameProfile); // Paper - update profile cache } @Override @@ -171,35 +171,35 @@ - Thread thread = new Thread("User Authenticator #" + UNIQUE_THREAD_ID.incrementAndGet()) { + // Paper start - Cache authenticator threads + authenticatorPool.execute(new Runnable() { - @Override - public void run() { - String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); -@@ -198,12 +_,18 @@ - .hasJoinedServer(string1, string, this.getAddress()); - if (profileResult != null) { - GameProfile gameProfile = profileResult.profile(); + { + Objects.requireNonNull(ServerLoginPacketListenerImpl.this); + } +@@ -202,12 +_,18 @@ + .hasJoinedServer(name, digest, this.getAddress()); + if (result != null) { + GameProfile profile = result.profile(); + // CraftBukkit start - fire PlayerPreLoginEvent + if (!ServerLoginPacketListenerImpl.this.connection.isConnected()) { + return; + } -+ gameProfile = ServerLoginPacketListenerImpl.this.callPlayerPreLoginEvents(gameProfile); // Paper - Add more fields to AsyncPlayerPreLoginEvent ++ profile = ServerLoginPacketListenerImpl.this.callPlayerPreLoginEvents(profile); // Paper - Add more fields to AsyncPlayerPreLoginEvent + // CraftBukkit end - ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameProfile.name(), gameProfile.id()); + ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", profile.name(), profile.id()); ServerLoginPacketListenerImpl.this.serverActivityMonitor.reportLoginActivity(); - ServerLoginPacketListenerImpl.this.startClientVerification(gameProfile); + ServerLoginPacketListenerImpl.this.startClientVerification(profile); } else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) { ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!"); -- ServerLoginPacketListenerImpl.this.startClientVerification(UUIDUtil.createOfflineProfile(string1)); -+ ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(string1)); // Spigot +- ServerLoginPacketListenerImpl.this.startClientVerification(UUIDUtil.createOfflineProfile(name)); ++ ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(name)); // Spigot } else { ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username")); - ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", string1); -@@ -211,11 +_,16 @@ + ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", name); +@@ -215,11 +_,16 @@ } catch (AuthenticationUnavailableException var4) { if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) { ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!"); -- ServerLoginPacketListenerImpl.this.startClientVerification(UUIDUtil.createOfflineProfile(string1)); -+ ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(string1)); // Spigot +- ServerLoginPacketListenerImpl.this.startClientVerification(UUIDUtil.createOfflineProfile(name)); ++ ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(name)); // Spigot } else { - ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); + ServerLoginPacketListenerImpl.this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown)); // Paper - Configurable kick message @@ -208,12 +208,12 @@ + // CraftBukkit start - catch all exceptions + } catch (Exception ex) { + ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); -+ ServerLoginPacketListenerImpl.LOGGER.warn("Exception verifying {}", string1, ex); ++ ServerLoginPacketListenerImpl.LOGGER.warn("Exception verifying {}", name, ex); + // CraftBukkit end } } -@@ -225,18 +_,123 @@ +@@ -229,18 +_,123 @@ ? ((InetSocketAddress)remoteAddress).getAddress() : null; } @@ -277,7 +277,7 @@ + // CraftBukkit end @Override - public void handleCustomQueryPacket(ServerboundCustomQueryAnswerPacket packet) { + public void handleCustomQueryPacket(final ServerboundCustomQueryAnswerPacket packet) { + // Paper start - Add Velocity IP Forwarding Support + try { + this.handleCustomQueryPacket0(packet); @@ -288,7 +288,7 @@ + } + } + } -+ private void handleCustomQueryPacket0(ServerboundCustomQueryAnswerPacket packet) { ++ private void handleCustomQueryPacket0(final ServerboundCustomQueryAnswerPacket packet) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.transactionId() == this.velocityLoginMessageId) { + ServerboundCustomQueryAnswerPacket.QueryAnswerPayload payload = (ServerboundCustomQueryAnswerPacket.QueryAnswerPayload)packet.payload(); + if (payload == null) { @@ -336,15 +336,15 @@ } @Override - public void handleLoginAcknowledgement(ServerboundLoginAcknowledgedPacket packet) { + public void handleLoginAcknowledgement(final ServerboundLoginAcknowledgedPacket packet) { + net.minecraft.network.protocol.PacketUtils.ensureRunningOnSameThread(packet, this, this.server.packetProcessor()); // CraftBukkit Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); - CommonListenerCookie commonListenerCookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred); -@@ -255,8 +_,31 @@ + CommonListenerCookie cookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred); +@@ -257,8 +_,31 @@ @Override - public void handleCookieResponse(ServerboundCookieResponsePacket packet) { + public void handleCookieResponse(final ServerboundCookieResponsePacket packet) { + if (this.paperLoginConnection.handleCookieResponse(packet)) return; // Paper this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); } diff --git a/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch b/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch index 616349a9566f..dcb6933c8c1f 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch @@ -1,18 +1,19 @@ --- a/net/minecraft/server/network/config/PrepareSpawnTask.java +++ b/net/minecraft/server/network/config/PrepareSpawnTask.java -@@ -36,10 +_,17 @@ - final LevelLoadListener loadListener; +@@ -37,10 +_,18 @@ + private final LevelLoadListener loadListener; private PrepareSpawnTask.@Nullable State state; -- public PrepareSpawnTask(MinecraftServer server, NameAndId nameAndId) { +- public PrepareSpawnTask(final MinecraftServer server, final NameAndId nameAndId) { + // Paper start - passthrough profile and packet listener + private final com.mojang.authlib.GameProfile profile; + private final net.minecraft.server.network.ServerConfigurationPacketListenerImpl listener; + private boolean newPlayer; -+ public PrepareSpawnTask(MinecraftServer server, com.mojang.authlib.GameProfile profile, net.minecraft.server.network.ServerConfigurationPacketListenerImpl listener) { ++ ++ public PrepareSpawnTask(final MinecraftServer server, final com.mojang.authlib.GameProfile profile, final net.minecraft.server.network.ServerConfigurationPacketListenerImpl listener) { + this.profile = profile; + this.listener = listener; -+ // Paper end - passthrough profile and packet listener ++ // Paper end - passthrough profile and packet listener this.server = server; - this.nameAndId = nameAndId; - this.loadListener = server.getLevelLoadListener(); @@ -21,18 +22,18 @@ } @Override -@@ -49,15 +_,57 @@ +@@ -50,16 +_,58 @@ .getPlayerList() .loadPlayerData(this.nameAndId) - .map(compoundTag -> TagValueInput.create(scopedCollector, this.server.registryAccess(), compoundTag)); + .map(tag -> TagValueInput.create(reporter, this.server.registryAccess(), tag)); + // Paper start - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found -+ this.newPlayer = optional.isEmpty(); // New players don't have saved data! ++ this.newPlayer = loadedData.isEmpty(); // New players don't have saved data! + net.minecraft.resources.ResourceKey resourceKey = null; // Paper + boolean[] invalidPlayerWorld = {false}; -+ bukkitData: if (optional.isPresent()) { ++ bukkitData: if (loadedData.isPresent()) { + // The main way for bukkit worlds to store the world is the world UUID despite mojang adding custom worlds + final org.bukkit.World bWorld; -+ final ValueInput playerData = optional.get(); ++ final ValueInput playerData = loadedData.get(); + // TODO maybe convert this to a codec and use compoundTag#read, we need silent variants of that method first. + final Optional worldUUIDMost = playerData.getLong("WorldUUIDMost"); + final Optional worldUUIDLeast = playerData.getLong("WorldUUIDLeast"); @@ -51,42 +52,44 @@ + invalidPlayerWorld[0] = true; + } + } - ServerPlayer.SavedPosition savedPosition = optional.flatMap( - valueInput -> valueInput.read(ServerPlayer.SavedPosition.MAP_CODEC) - ) + ServerPlayer.SavedPosition loadedPosition = loadedData.flatMap(tag -> tag.read(ServerPlayer.SavedPosition.MAP_CODEC)) .orElse(ServerPlayer.SavedPosition.EMPTY); LevelData.RespawnData respawnData = this.server.getWorldData().overworldData().getRespawnData(); -- ServerLevel serverLevel = savedPosition.dimension().map(this.server::getLevel).orElseGet(() -> { -- ServerLevel level = this.server.getLevel(respawnData.dimension()); -- return level != null ? level : this.server.overworld(); +- ServerLevel spawnLevel = loadedPosition.dimension().map(this.server::getLevel).orElseGet(() -> { +- ServerLevel spawnDataLevel = this.server.getLevel(respawnData.dimension()); +- return spawnDataLevel != null ? spawnDataLevel : this.server.overworld(); - }); + if (resourceKey == null) { // only run the vanilla logic if we haven't found a world from the bukkit data + // Below is the vanilla way of getting the dimension, this is for migration from vanilla servers -+ resourceKey = savedPosition.dimension().orElse(null); ++ resourceKey = loadedPosition.dimension().orElse(null); + } -+ ServerLevel vanillaDefaultLevel = this.server.getLevel(respawnData.dimension()); -+ if (vanillaDefaultLevel == null) { -+ vanillaDefaultLevel = this.server.overworld(); ++ ServerLevel spawnDataLevel = this.server.getLevel(respawnData.dimension()); ++ if (spawnDataLevel == null) { ++ spawnDataLevel = this.server.overworld(); + } -+ ServerLevel serverLevel1; ++ ServerLevel spawnLevel; + if (resourceKey == null) { -+ serverLevel1 = vanillaDefaultLevel; ++ spawnLevel = spawnDataLevel; + } else { -+ serverLevel1 = this.server.getLevel(resourceKey); -+ if (serverLevel1 == null) { ++ spawnLevel = this.server.getLevel(resourceKey); ++ if (spawnLevel == null) { + LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourceKey); -+ serverLevel1 = vanillaDefaultLevel; ++ spawnLevel = spawnDataLevel; + } + } -+ final ServerLevel serverLevel = serverLevel1; -+ // Paper end - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found - CompletableFuture completableFuture = savedPosition.position() ++ final ServerLevel finalSpawnLevel = spawnLevel; + CompletableFuture spawnPosition = loadedPosition.position() .map(CompletableFuture::completedFuture) - .orElseGet(() -> PlayerSpawnFinder.findSpawn(serverLevel, respawnData.pos())); -@@ -112,10 +_,11 @@ +- .orElseGet(() -> PlayerSpawnFinder.findSpawn(spawnLevel, respawnData.pos())); ++ .orElseGet(() -> PlayerSpawnFinder.findSpawn(finalSpawnLevel, respawnData.pos())); ++ // Paper end - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found + Vec2 spawnAngle = loadedPosition.rotation().orElse(new Vec2(respawnData.yaw(), respawnData.pitch())); + this.state = new PrepareSpawnTask.Preparing(spawnLevel, spawnPosition, spawnAngle); + } +@@ -111,10 +_,11 @@ } - final class Preparing implements PrepareSpawnTask.State { + private final class Preparing implements PrepareSpawnTask.State { - private final ServerLevel spawnLevel; - private final CompletableFuture spawnPosition; - private final Vec2 spawnAngle; @@ -95,40 +98,44 @@ + private Vec2 spawnAngle; // Paper - remove final private @Nullable CompletableFuture chunkLoadFuture; + private @Nullable CompletableFuture eventFuture; // Paper - private final ChunkLoadCounter chunkLoadCounter = new ChunkLoadCounter(); + private final ChunkLoadCounter chunkLoadCounter; - Preparing(final ServerLevel spawnLevel, final CompletableFuture spawnPosition, final Vec2 spawnAngle) { -@@ -134,6 +_,50 @@ + private Preparing(final ServerLevel spawnLevel, final CompletableFuture spawnPosition, final Vec2 spawnAngle) { +@@ -136,6 +_,54 @@ } else { - Vec3 vec3 = this.spawnPosition.join(); + Vec3 spawnPosition = this.spawnPosition.join(); if (this.chunkLoadFuture == null) { + // Paper start - PlayerSpawnLocationEvent + if (this.eventFuture == null && org.spigotmc.event.player.PlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { -+ ServerPlayer serverPlayer; ++ ServerPlayer player; + if (PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents != null) { -+ serverPlayer = PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents; ++ player = PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents; + } else { -+ serverPlayer = new ServerPlayer( -+ PrepareSpawnTask.this.server, PrepareSpawnTask.this.server.overworld(), PrepareSpawnTask.this.profile, net.minecraft.server.level.ClientInformation.createDefault()); -+ PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents = serverPlayer; ++ player = new ServerPlayer( ++ PrepareSpawnTask.this.server, ++ PrepareSpawnTask.this.server.overworld(), ++ PrepareSpawnTask.this.profile, ++ net.minecraft.server.level.ClientInformation.createDefault() ++ ); ++ PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents = player; + } + org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent( -+ serverPlayer.getBukkitEntity(), -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(vec3, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y) ++ player.getBukkitEntity(), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPosition, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y) + ); + ev.callEvent(); -+ vec3 = io.papermc.paper.util.MCUtil.toVec3(ev.getSpawnLocation()); ++ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(ev.getSpawnLocation()); + this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) ev.getSpawnLocation().getWorld()).getHandle(); -+ this.spawnPosition = CompletableFuture.completedFuture(vec3); ++ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); + this.spawnAngle = new Vec2(ev.getSpawnLocation().getYaw(), ev.getSpawnLocation().getPitch()); + } + + if (this.eventFuture == null && io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { -+ final Vec3 vec3final = vec3; ++ final Vec3 spawnPositionFinal = spawnPosition; + this.eventFuture = CompletableFuture.supplyAsync(() -> { + io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent ev = new io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent( + PrepareSpawnTask.this.listener.paperConnection, -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(vec3final, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPositionFinal, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y), + PrepareSpawnTask.this.newPlayer + ); + ev.callEvent(); @@ -140,62 +147,62 @@ + return null; + } + org.bukkit.Location location = this.eventFuture.join(); -+ vec3 = io.papermc.paper.util.MCUtil.toVec3(location); ++ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(location); + this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(); -+ this.spawnPosition = CompletableFuture.completedFuture(vec3); ++ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); + this.spawnAngle = new Vec2(location.getYaw(), location.getPitch()); + } + // Paper end - PlayerSpawnLocationEvent - ChunkPos chunkPos = new ChunkPos(BlockPos.containing(vec3)); + ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition)); this.chunkLoadCounter .track( -@@ -174,15 +_,48 @@ - public ServerPlayer spawn(Connection connection, CommonListenerCookie cookie) { - ChunkPos chunkPos = new ChunkPos(BlockPos.containing(this.spawnPosition)); - this.spawnLevel.waitForEntities(chunkPos, 3); -- ServerPlayer serverPlayer = new ServerPlayer(PrepareSpawnTask.this.server, this.spawnLevel, cookie.gameProfile(), cookie.clientInformation()); +@@ -178,15 +_,48 @@ + public ServerPlayer spawn(final Connection connection, final CommonListenerCookie cookie) { + ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(this.spawnPosition)); + this.spawnLevel.waitForEntities(spawnChunk, 3); +- ServerPlayer player = new ServerPlayer(PrepareSpawnTask.this.server, this.spawnLevel, cookie.gameProfile(), cookie.clientInformation()); + // Paper start - configuration api - possibly use legacy saved server player instance -+ ServerPlayer serverPlayer; ++ ServerPlayer player; + if (connection.savedPlayerForLegacyEvents != null) { -+ serverPlayer = connection.savedPlayerForLegacyEvents; ++ player = connection.savedPlayerForLegacyEvents; + connection.savedPlayerForLegacyEvents = null; + // Update the existing instance -+ serverPlayer.gameProfile = cookie.gameProfile(); -+ serverPlayer.updateOptionsNoEvents(cookie.clientInformation()); -+ serverPlayer.setServerLevel(this.spawnLevel); ++ player.gameProfile = cookie.gameProfile(); ++ player.updateOptionsNoEvents(cookie.clientInformation()); ++ player.setServerLevel(this.spawnLevel); + } else { -+ serverPlayer = new ServerPlayer(PrepareSpawnTask.this.server, this.spawnLevel, cookie.gameProfile(), cookie.clientInformation()); ++ player = new ServerPlayer(PrepareSpawnTask.this.server, this.spawnLevel, cookie.gameProfile(), cookie.clientInformation()); + } + // Paper end - configuration api - possibly use legacy saved server player instance ServerPlayer var7; - try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), PrepareSpawnTask.LOGGER)) { - Optional optional = PrepareSpawnTask.this.server + try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(player.problemPath(), PrepareSpawnTask.LOGGER)) { + Optional input = PrepareSpawnTask.this.server .getPlayerList() .loadPlayerData(PrepareSpawnTask.this.nameAndId) + // CraftBukkit start + .map(tag -> { -+ org.bukkit.craftbukkit.entity.CraftPlayer craftPlayer = serverPlayer.getBukkitEntity(); ++ org.bukkit.craftbukkit.entity.CraftPlayer craftPlayer = player.getBukkitEntity(); + // Only update first played if it is older than the one we have -+ long modified = new java.io.File(net.minecraft.server.network.config.PrepareSpawnTask.this.server.playerDataStorage.getPlayerDir(), serverPlayer.getStringUUID() + ".dat").lastModified(); ++ long modified = new java.io.File(net.minecraft.server.network.config.PrepareSpawnTask.this.server.playerDataStorage.getPlayerDir(), player.getStringUUID() + ".dat").lastModified(); + if (modified < craftPlayer.getFirstPlayed()) { + craftPlayer.setFirstPlayed(modified); + } + return tag; + }) + // CraftBukkit end - .map(compoundTag -> TagValueInput.create(scopedCollector, PrepareSpawnTask.this.server.registryAccess(), compoundTag)); - optional.ifPresent(serverPlayer::load); + .map(tag -> TagValueInput.create(reporter, PrepareSpawnTask.this.server.registryAccess(), tag)); + input.ifPresent(player::load); + // CraftBukkit start - Better rename detection -+ if (optional.isPresent()) { -+ serverPlayer.lastKnownName = optional.flatMap(t -> t.child("bukkit")).flatMap(t -> t.getString("lastKnownName")).orElse(null); ++ if (input.isPresent()) { ++ player.lastKnownName = input.flatMap(t -> t.child("bukkit")).flatMap(t -> t.getString("lastKnownName")).orElse(null); + } + // CraftBukkit end - Better rename detection + // Paper start - Entity#getEntitySpawnReason -+ if (optional.isEmpty()) { -+ serverPlayer.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login ++ if (input.isEmpty()) { ++ player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login + } + // Paper end - Entity#getEntitySpawnReason - serverPlayer.snapTo(this.spawnPosition, this.spawnAngle.x, this.spawnAngle.y); - PrepareSpawnTask.this.server.getPlayerList().placeNewPlayer(connection, serverPlayer, cookie); - optional.ifPresent(valueInput -> { + player.snapTo(this.spawnPosition, this.spawnAngle.x, this.spawnAngle.y); + PrepareSpawnTask.this.server.getPlayerList().placeNewPlayer(connection, player, cookie); + input.ifPresent(tag -> { diff --git a/paper-server/patches/sources/net/minecraft/server/notifications/EmptyNotificationService.java.patch b/paper-server/patches/sources/net/minecraft/server/notifications/EmptyNotificationService.java.patch index 83ebfe93a472..5f5327fe09bc 100644 --- a/paper-server/patches/sources/net/minecraft/server/notifications/EmptyNotificationService.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/notifications/EmptyNotificationService.java.patch @@ -4,8 +4,8 @@ } @Override -- public void onGameRuleChanged(GameRule rule, T value) { -+ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, GameRule rule, T value) { // Paper - per-world game rules (add level param) +- public void onGameRuleChanged(final GameRule gameRule, final T value) { ++ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, final GameRule gameRule, final T value) { // Paper - per-world game rules (add level param) } @Override diff --git a/paper-server/patches/sources/net/minecraft/server/notifications/NotificationManager.java.patch b/paper-server/patches/sources/net/minecraft/server/notifications/NotificationManager.java.patch index 9caace376939..fedd4f653880 100644 --- a/paper-server/patches/sources/net/minecraft/server/notifications/NotificationManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/notifications/NotificationManager.java.patch @@ -4,10 +4,10 @@ } @Override -- public void onGameRuleChanged(GameRule rule, T value) { -- this.notificationServices.forEach(notificationService -> notificationService.onGameRuleChanged(rule, value)); -+ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, GameRule rule, T value) { // Paper - per-world game rules (add level param) -+ this.notificationServices.forEach(notificationService -> notificationService.onGameRuleChanged(level, rule, value)); // Paper - per-world game rules (add level param) +- public void onGameRuleChanged(final GameRule gameRule, final T value) { +- this.notificationServices.forEach(notificationService -> notificationService.onGameRuleChanged(gameRule, value)); ++ public void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, final GameRule gameRule, final T value) { // Paper - per-world game rules (add level param) ++ this.notificationServices.forEach(notificationService -> notificationService.onGameRuleChanged(level, gameRule, value)); // Paper - per-world game rules (add level param) } @Override diff --git a/paper-server/patches/sources/net/minecraft/server/notifications/NotificationService.java.patch b/paper-server/patches/sources/net/minecraft/server/notifications/NotificationService.java.patch index 735ae3988d81..245395a1a69b 100644 --- a/paper-server/patches/sources/net/minecraft/server/notifications/NotificationService.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/notifications/NotificationService.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/server/notifications/NotificationService.java @@ -38,7 +_,7 @@ - void playerUnbanned(NameAndId nameAndId); + void playerUnbanned(NameAndId player); -- void onGameRuleChanged(GameRule rule, T value); -+ void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, GameRule rule, T value); // Paper - per-world game rules (add level param) +- void onGameRuleChanged(GameRule gameRule, T value); ++ void onGameRuleChanged(net.minecraft.server.level.ServerLevel level, GameRule gameRule, T value); // Paper - per-world game rules (add level param) void statusHeartbeat(); } diff --git a/paper-server/patches/sources/net/minecraft/server/packs/PathPackResources.java.patch b/paper-server/patches/sources/net/minecraft/server/packs/PathPackResources.java.patch deleted file mode 100644 index 95ae2eebfd30..000000000000 --- a/paper-server/patches/sources/net/minecraft/server/packs/PathPackResources.java.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/net/minecraft/server/packs/PathPackResources.java -+++ b/net/minecraft/server/packs/PathPackResources.java -@@ -120,6 +_,12 @@ - try (DirectoryStream directoryStream = Files.newDirectoryStream(path)) { - for (Path path1 : directoryStream) { - String string = path1.getFileName().toString(); -+ // Paper start - Improve logging and errors -+ if (!Files.isDirectory(path1)) { -+ LOGGER.error("Invalid directory entry: {} in {}.", string, this.root, new java.nio.file.NotDirectoryException(string)); -+ continue; -+ } -+ // Paper end - Improve logging and errors - if (Identifier.isValidNamespace(string)) { - set.add(string); - } else { diff --git a/paper-server/patches/sources/net/minecraft/server/packs/repository/PackRepository.java.patch b/paper-server/patches/sources/net/minecraft/server/packs/repository/PackRepository.java.patch index 8a7d513c121f..4a1a6588aaa1 100644 --- a/paper-server/patches/sources/net/minecraft/server/packs/repository/PackRepository.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/packs/repository/PackRepository.java.patch @@ -1,21 +1,19 @@ --- a/net/minecraft/server/packs/repository/PackRepository.java +++ b/net/minecraft/server/packs/repository/PackRepository.java -@@ -21,9 +_,13 @@ +@@ -21,8 +_,12 @@ private final Set sources; private Map available = ImmutableMap.of(); private List selected = ImmutableList.of(); + private final net.minecraft.world.level.validation.DirectoryValidator validator; // Paper - add validator -- public PackRepository(RepositorySource... sources) { -- this.sources = ImmutableSet.copyOf(sources); +- public PackRepository(final RepositorySource... sources) { + // Paper start - add validator -+ public PackRepository(net.minecraft.world.level.validation.DirectoryValidator validator, RepositorySource... providers) { ++ public PackRepository(final net.minecraft.world.level.validation.DirectoryValidator validator, final RepositorySource... sources) { + this.validator = validator; + // Paper end - add validator -+ this.sources = ImmutableSet.copyOf(providers); + this.sources = ImmutableSet.copyOf(sources); } - public static String displayPackList(Collection packs) { @@ -31,9 +_,14 @@ } @@ -25,20 +23,20 @@ + } + public void reload(final boolean pendingReload) { + // Paper end - add pendingReload flag to determine required pack loading - List list = this.selected.stream().map(Pack::getId).collect(ImmutableList.toImmutableList()); + List currentlySelectedNames = this.selected.stream().map(Pack::getId).collect(ImmutableList.toImmutableList()); this.available = this.discoverAvailable(); -- this.selected = this.rebuildSelected(list); -+ this.selected = this.rebuildSelected(list, pendingReload); // Paper - add pendingReload flag to determine required pack loading +- this.selected = this.rebuildSelected(currentlySelectedNames); ++ this.selected = this.rebuildSelected(currentlySelectedNames, pendingReload); // Paper - add pendingReload flag to determine required pack loading } private Map discoverAvailable() { @@ -43,16 +_,23 @@ - repositorySource.loadPacks(pack -> map.put(pack.getId(), pack)); + source.loadPacks(pack -> discovered.put(pack.getId(), pack)); } -- return ImmutableMap.copyOf(map); +- return ImmutableMap.copyOf(discovered); + // Paper start - custom plugin-loaded datapacks -+ final io.papermc.paper.datapack.PaperDatapackRegistrar registrar = new io.papermc.paper.datapack.PaperDatapackRegistrar(this.validator, map); ++ final io.papermc.paper.datapack.PaperDatapackRegistrar registrar = new io.papermc.paper.datapack.PaperDatapackRegistrar(this.validator, discovered); + io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callStaticRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.DATAPACK_DISCOVERY, + registrar, + io.papermc.paper.plugin.bootstrap.BootstrapContext.class @@ -48,29 +46,29 @@ } public boolean isAbleToClearAnyPack() { -- List list = this.rebuildSelected(List.of()); -+ List list = this.rebuildSelected(List.of(), false); // Paper - add pendingReload flag to determine required pack loading - return !this.selected.equals(list); +- List newSelected = this.rebuildSelected(List.of()); ++ List newSelected = this.rebuildSelected(List.of(), false); // Paper - add pendingReload flag to determine required pack loading + return !this.selected.equals(newSelected); } -- public void setSelected(Collection ids) { -- this.selected = this.rebuildSelected(ids); -+ public void setSelected(Collection ids, final boolean pendingReload) { // Paper - add pendingReload flag to determine required pack loading -+ this.selected = this.rebuildSelected(ids, pendingReload); // Paper - add pendingReload flag to determine required pack loading +- public void setSelected(final Collection packs) { +- this.selected = this.rebuildSelected(packs); ++ public void setSelected(final Collection packs, final boolean pendingReload) { // Paper - add pendingReload flag to determine required pack loading ++ this.selected = this.rebuildSelected(packs, pendingReload); // Paper - add pendingReload flag to determine required pack loading } - public boolean addPack(String id) { + public boolean addPack(final String packId) { @@ -79,11 +_,11 @@ } } -- private List rebuildSelected(Collection ids) { -+ private List rebuildSelected(Collection ids, boolean pendingReload) { // Paper - add pendingReload flag to determine required pack loading - List list = this.getAvailablePacks(ids).collect(Util.toMutableList()); +- private List rebuildSelected(final Collection selectedNames) { ++ private List rebuildSelected(final Collection selectedNames, final boolean pendingReload) { // Paper - add pendingReload flag to determine required pack loading + List selectedAndPresent = this.getAvailablePacks(selectedNames).collect(Util.toMutableList()); for (Pack pack : this.available.values()) { -- if (pack.isRequired() && !list.contains(pack)) { -+ if (pack.isRequired() && !list.contains(pack) && pendingReload) { // Paper - add pendingReload flag to determine required pack loading - pack.getDefaultPosition().insert(list, pack, Pack::selectionConfig, false); +- if (pack.isRequired() && !selectedAndPresent.contains(pack)) { ++ if (pack.isRequired() && !selectedAndPresent.contains(pack) && pendingReload) { // Paper - add pendingReload flag to determine required pack loading + pack.getDefaultPosition().insert(selectedAndPresent, pack, Pack::selectionConfig, false); } } diff --git a/paper-server/patches/sources/net/minecraft/server/packs/repository/ServerPacksSource.java.patch b/paper-server/patches/sources/net/minecraft/server/packs/repository/ServerPacksSource.java.patch index dbb1f23f29a0..2e6f9eefb06b 100644 --- a/paper-server/patches/sources/net/minecraft/server/packs/repository/ServerPacksSource.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/packs/repository/ServerPacksSource.java.patch @@ -12,25 +12,25 @@ @@ -66,15 +_,26 @@ @Override - protected @Nullable Pack createBuiltinPack(String id, Pack.ResourcesSupplier resources, Component title) { -- return Pack.readMetaAndCreate(createBuiltInPackLocation(id, title), resources, PackType.SERVER_DATA, FEATURE_SELECTION_CONFIG); + protected @Nullable Pack createBuiltinPack(final String id, final Pack.ResourcesSupplier resources, final Component name) { +- return Pack.readMetaAndCreate(createBuiltInPackLocation(id, name), resources, PackType.SERVER_DATA, FEATURE_SELECTION_CONFIG); + // Paper start - custom built-in pack + final PackLocationInfo info; + final PackSelectionConfig packConfig; + if ("paper".equals(id)) { -+ info = new PackLocationInfo(id, title, PackSource.BUILT_IN, Optional.empty()); ++ info = new PackLocationInfo(id, name, PackSource.BUILT_IN, Optional.empty()); + packConfig = new PackSelectionConfig(true, Pack.Position.TOP, true); + } else { -+ info = createBuiltInPackLocation(id, title); ++ info = createBuiltInPackLocation(id, name); + packConfig = FEATURE_SELECTION_CONFIG; + } + return Pack.readMetaAndCreate(info, resources, PackType.SERVER_DATA, packConfig); + // Paper end - custom built-in pack } - public static PackRepository createPackRepository(Path folder, DirectoryValidator validator) { -- return new PackRepository(new ServerPacksSource(validator), new FolderRepositorySource(folder, PackType.SERVER_DATA, PackSource.WORLD, validator)); -+ return new PackRepository(validator, new ServerPacksSource(validator), new FolderRepositorySource(folder, PackType.SERVER_DATA, PackSource.WORLD, validator)); // Paper - add validator + public static PackRepository createPackRepository(final Path datapackDir, final DirectoryValidator validator) { +- return new PackRepository(new ServerPacksSource(validator), new FolderRepositorySource(datapackDir, PackType.SERVER_DATA, PackSource.WORLD, validator)); ++ return new PackRepository(validator, new ServerPacksSource(validator), new FolderRepositorySource(datapackDir, PackType.SERVER_DATA, PackSource.WORLD, validator)); // Paper - add validator } public static PackRepository createVanillaTrustedRepository() { @@ -38,4 +38,4 @@ + return new PackRepository(new DirectoryValidator(path -> true), new ServerPacksSource(new DirectoryValidator(path -> true))); // Paper - add validator } - public static PackRepository createPackRepository(LevelStorageSource.LevelStorageAccess level) { + public static PackRepository createPackRepository(final LevelStorageSource.LevelStorageAccess levelSourceAccess) { diff --git a/paper-server/patches/sources/net/minecraft/server/permissions/PermissionProviderCheck.java.patch b/paper-server/patches/sources/net/minecraft/server/permissions/PermissionProviderCheck.java.patch index 205aa6425bd4..4c9ecf6a297d 100644 --- a/paper-server/patches/sources/net/minecraft/server/permissions/PermissionProviderCheck.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/permissions/PermissionProviderCheck.java.patch @@ -7,14 +7,14 @@ -public record PermissionProviderCheck(PermissionCheck test) implements Predicate { +public record PermissionProviderCheck(PermissionCheck test, java.util.concurrent.atomic.AtomicReference> vanillaNode) implements Predicate { // Paper - Vanilla Command permission checking @Override - public boolean test(T permissionsSupplier) { + public boolean test(final T t) { + // Paper start - Vanilla Command permission checking + com.mojang.brigadier.tree.CommandNode currentCommand = vanillaNode.get(); -+ if (currentCommand != null && permissionsSupplier instanceof net.minecraft.commands.CommandSourceStack commandSourceStack && this.test instanceof net.minecraft.server.permissions.PermissionCheck.Require req) { ++ if (currentCommand != null && t instanceof net.minecraft.commands.CommandSourceStack commandSourceStack && this.test instanceof net.minecraft.server.permissions.PermissionCheck.Require req) { + return commandSourceStack.hasPermission(req.permission(), org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand)); + } + // Paper end - Vanilla Command permission checking - return this.test.check(permissionsSupplier.permissions()); + return this.test.check(t.permissions()); } + + // Paper start - Vanilla Command permission checking diff --git a/paper-server/patches/sources/net/minecraft/server/players/BanListEntry.java.patch b/paper-server/patches/sources/net/minecraft/server/players/BanListEntry.java.patch index adebe9c189b2..3509a5098176 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/BanListEntry.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/BanListEntry.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/server/players/BanListEntry.java +++ b/net/minecraft/server/players/BanListEntry.java -@@ -26,7 +_,7 @@ +@@ -28,7 +_,7 @@ } - protected BanListEntry(@Nullable T user, JsonObject entryData) { + protected BanListEntry(final @Nullable T user, final JsonObject object) { - super(user); -+ super(BanListEntry.checkExpiry(user, entryData)); // CraftBukkit ++ super(BanListEntry.checkExpiry(user, object)); // CraftBukkit - Date date; + Date created; try { -@@ -99,4 +_,22 @@ +@@ -101,4 +_,22 @@ return false; } } diff --git a/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch b/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch index cdbf2f1a6c97..8da762b0a07c 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch @@ -9,12 +9,12 @@ + protected final java.util.concurrent.locks.ReentrantLock lookupLock = new java.util.concurrent.locks.ReentrantLock(); + // Paper end - Fix GameProfileCache concurrency - public CachedUserNameToIdResolver(GameProfileRepository profileRepository, File file) { + public CachedUserNameToIdResolver(final GameProfileRepository profileRepository, final File file) { this.profileRepository = profileRepository; @@ -54,23 +_,27 @@ } - private void safeAdd(CachedUserNameToIdResolver.GameProfileInfo profileInfo) { + private void safeAdd(final CachedUserNameToIdResolver.GameProfileInfo profileInfo) { + try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency NameAndId nameAndId = profileInfo.nameAndId(); profileInfo.setLastAccess(this.getNextOperation()); @@ -23,31 +23,31 @@ + } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency } - private Optional lookupGameProfile(GameProfileRepository profileRepository, String name) { + private Optional lookupGameProfile(final GameProfileRepository profileRepository, final String name) { if (!StringUtil.isValidPlayerName(name)) { return this.createUnknownProfile(name); } else { -- Optional optional = profileRepository.findProfileByName(name).map(NameAndId::new); -+ final boolean shouldLookup = !org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name +- Optional profile = profileRepository.findProfileByName(name).map(NameAndId::new); ++ final boolean shouldLookup = !org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name + && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper - Add setting for proxy online mode status -+ Optional optional = shouldLookup ? profileRepository.findProfileByName(name).map(NameAndId::new) : Optional.empty(); // Paper - Don't lookup a profile with a blank name - return optional.isEmpty() ? this.createUnknownProfile(name) : optional; ++ Optional profile = shouldLookup ? profileRepository.findProfileByName(name).map(NameAndId::new) : Optional.empty(); // Paper - Don't lookup a profile with a blank name + return profile.isEmpty() ? this.createUnknownProfile(name) : profile; } } - private Optional createUnknownProfile(String name) { + private Optional createUnknownProfile(final String name) { - return this.resolveOfflineUsers ? Optional.of(NameAndId.createOffline(name)) : Optional.empty(); -+ return !io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? Optional.of(NameAndId.createOffline(name)) : Optional.empty(); // Paper - Add setting for proxy online mode status ++ return this.resolveOfflineUsers && !io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? Optional.of(NameAndId.createOffline(name)) : Optional.empty(); // Paper - Add setting for proxy online mode status } @Override @@ -90,7 +_,7 @@ - Date time = instance.getTime(); - CachedUserNameToIdResolver.GameProfileInfo gameProfileInfo = new CachedUserNameToIdResolver.GameProfileInfo(nameAndId, time); - this.safeAdd(gameProfileInfo); + Date expirationDate = c.getTime(); + CachedUserNameToIdResolver.GameProfileInfo profileInfo = new CachedUserNameToIdResolver.GameProfileInfo(profile, expirationDate); + this.safeAdd(profileInfo); - this.save(); + if (!org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) this.save(true); // Spigot - skip saving if disabled // Paper - Perf: Async GameProfileCache saving - return gameProfileInfo; + return profileInfo; } @@ -98,9 +_,24 @@ @@ -56,7 +56,7 @@ + // Paper start + @Override -+ public @javax.annotation.Nullable NameAndId getIfCached(String name) { ++ public @org.jspecify.annotations.Nullable NameAndId getIfCached(final String name) { + try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + CachedUserNameToIdResolver.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT)); + if (entry == null) { @@ -69,50 +69,50 @@ + // Paper end + @Override - public Optional get(String name) { - String string = name.toLowerCase(Locale.ROOT); + public Optional get(final String name) { + String userName = name.toLowerCase(Locale.ROOT); + boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - CachedUserNameToIdResolver.GameProfileInfo gameProfileInfo = this.profilesByName.get(string); - boolean flag = false; - if (gameProfileInfo != null && new Date().getTime() >= gameProfileInfo.expirationDate.getTime()) { + CachedUserNameToIdResolver.GameProfileInfo profileInfo = this.profilesByName.get(userName); + boolean needsSave = false; + if (profileInfo != null && new Date().getTime() >= profileInfo.expirationDate.getTime()) { @@ -114,8 +_,13 @@ - if (gameProfileInfo != null) { - gameProfileInfo.setLastAccess(this.getNextOperation()); - optional = Optional.of(gameProfileInfo.nameAndId()); + if (profileInfo != null) { + profileInfo.setLastAccess(this.getNextOperation()); + result = Optional.of(profileInfo.nameAndId()); + stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency } else { -- Optional optional1 = this.lookupGameProfile(this.profileRepository, string); -+ Optional optional1; +- Optional profile = this.lookupGameProfile(this.profileRepository, userName); ++ Optional profile; + stateLocked = false; this.stateLock.unlock(); // Paper - Fix GameProfileCache concurrency + try { this.lookupLock.lock(); // Paper - Fix GameProfileCache concurrency -+ optional1 = this.lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players ++ profile = this.lookupGameProfile(this.profileRepository, name); // CraftBukkit - use correct case for offline players + } finally { this.lookupLock.unlock(); } // Paper - Fix GameProfileCache concurrency - if (optional1.isPresent()) { - optional = Optional.of(this.addInternal(optional1.get()).nameAndId()); - flag = false; + if (profile.isPresent()) { + result = Optional.of(this.addInternal(profile.get()).nameAndId()); + needsSave = false; @@ -124,15 +_,17 @@ } } -- if (flag) { +- if (needsSave) { - this.save(); -+ if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled ++ if (needsSave && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled + this.save(true); // Paper - Perf: Async GameProfileCache saving } - return optional; + return result; + } finally { if (stateLocked) { this.stateLock.unlock(); } } // Paper - Fix GameProfileCache concurrency } @Override - public Optional get(UUID uuid) { + public Optional get(final UUID id) { + try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency - CachedUserNameToIdResolver.GameProfileInfo gameProfileInfo = this.profilesByUUID.get(uuid); - if (gameProfileInfo == null) { + CachedUserNameToIdResolver.GameProfileInfo profileInfo = this.profilesByUUID.get(id); + if (profileInfo == null) { return Optional.empty(); @@ -140,6 +_,7 @@ - gameProfileInfo.setLastAccess(this.getNextOperation()); - return Optional.of(gameProfileInfo.nameAndId()); + profileInfo.setLastAccess(this.getNextOperation()); + return Optional.of(profileInfo.nameAndId()); } + } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency } @@ -139,17 +139,17 @@ + } + + @Override -+ public void save(boolean asyncSave) { ++ public void save(final boolean asyncSave) { + // Paper end - Perf: Async GameProfileCache saving - JsonArray jsonArray = new JsonArray(); + JsonArray entryList = new JsonArray(); DateFormat dateFormat = createDateFormat(); -- this.getTopMRUProfiles(1000).forEach(gameProfileInfo -> jsonArray.add(writeGameProfile(gameProfileInfo, dateFormat))); -+ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach(gameProfileInfo -> jsonArray.add(writeGameProfile(gameProfileInfo, dateFormat))); // Spigot // Paper - Fix GameProfileCache concurrency - String string = this.gson.toJson((JsonElement)jsonArray); +- this.getTopMRUProfiles(1000).forEach(entry -> entryList.add(writeGameProfile(entry, dateFormat))); ++ this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach(entry -> entryList.add(writeGameProfile(entry, dateFormat))); // Spigot // Paper - Fix GameProfileCache concurrency + String toSave = this.gson.toJson((JsonElement)entryList); + Runnable save = () -> { // Paper - Perf: Async GameProfileCache saving try (Writer writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) { - writer.write(string); + writer.write(toSave); } catch (IOException var9) { } + // Paper start - Perf: Async GameProfileCache saving @@ -162,7 +162,7 @@ + // Paper end - Perf: Async GameProfileCache saving } - private Stream getTopMRUProfiles(int limit) { + private Stream getTopMRUProfiles(final int limit) { - return ImmutableList.copyOf(this.profilesByUUID.values()) - .stream() - .sorted(Comparator.comparing(CachedUserNameToIdResolver.GameProfileInfo::lastAccess).reversed()) @@ -172,7 +172,7 @@ + return this.listTopMRUProfiles(limit).stream(); + } + -+ private List listTopMRUProfiles(int limit) { ++ private List listTopMRUProfiles(final int limit) { + try { + this.stateLock.lock(); + return this.profilesByUUID.values() @@ -186,5 +186,5 @@ + } + // Paper end - Fix GameProfileCache concurrency - private static JsonElement writeGameProfile(CachedUserNameToIdResolver.GameProfileInfo profileInfo, DateFormat format) { - JsonObject jsonObject = new JsonObject(); + private static JsonElement writeGameProfile(final CachedUserNameToIdResolver.GameProfileInfo src, final DateFormat dateFormat) { + JsonObject object = new JsonObject(); diff --git a/paper-server/patches/sources/net/minecraft/server/players/NameAndId.java.patch b/paper-server/patches/sources/net/minecraft/server/players/NameAndId.java.patch index d8dcdd205edc..fa72307779cf 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/NameAndId.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/NameAndId.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/server/players/NameAndId.java +++ b/net/minecraft/server/players/NameAndId.java @@ -48,4 +_,10 @@ - UUID uuid = UUIDUtil.createOfflinePlayerUUID(name); - return new NameAndId(uuid, name); + UUID id = UUIDUtil.createOfflinePlayerUUID(name); + return new NameAndId(id, name); } + + // Paper start - utility method for common conversion back to the game profile diff --git a/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch b/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch index e479bb8a83ce..02d4bec2ed83 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch @@ -2,59 +2,59 @@ +++ b/net/minecraft/server/players/OldUsersConverter.java @@ -50,7 +_,8 @@ - private static void lookupPlayers(MinecraftServer server, Collection names, ProfileLookupCallback callback) { - String[] strings = names.stream().filter(name -> !StringUtil.isNullOrEmpty(name)).toArray(String[]::new); + private static void lookupPlayers(final MinecraftServer server, final Collection names, final ProfileLookupCallback callback) { + String[] filteredNames = names.stream().filter(s -> !StringUtil.isNullOrEmpty(s)).toArray(String[]::new); - if (server.usesAuthentication()) { + if (server.usesAuthentication() || + (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode())) { // Spigot: bungee = online mode, for now. // Paper - Add setting for proxy online mode status - server.services().profileRepository().findProfilesByNames(strings, callback); + server.services().profileRepository().findProfilesByNames(filteredNames, callback); } else { - for (String string : strings) { + for (String name : filteredNames) { @@ -66,7 +_,7 @@ try { - userBanList.load(); + bans.load(); } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", userBanList.getFile().getName(), var6); -+ LOGGER.warn("Could not load existing file {}", userBanList.getFile().getName()); // CraftBukkit - don't print stacktrace +- LOGGER.warn("Could not load existing file {}", bans.getFile().getName(), var6); ++ LOGGER.warn("Could not load existing file {}", bans.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -122,7 +_,7 @@ try { - ipBanList.load(); + ipBans.load(); } catch (IOException var11) { -- LOGGER.warn("Could not load existing file {}", ipBanList.getFile().getName(), var11); -+ LOGGER.warn("Could not load existing file {}", ipBanList.getFile().getName()); // CraftBukkit - don't print stacktrace +- LOGGER.warn("Could not load existing file {}", ipBans.getFile().getName(), var11); ++ LOGGER.warn("Could not load existing file {}", ipBans.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -158,7 +_,7 @@ try { - serverOpList.load(); + opsList.load(); } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", serverOpList.getFile().getName(), var6); -+ LOGGER.warn("Could not load existing file {}", serverOpList.getFile().getName()); // CraftBukkit - don't print stacktrace +- LOGGER.warn("Could not load existing file {}", opsList.getFile().getName(), var6); ++ LOGGER.warn("Could not load existing file {}", opsList.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -203,7 +_,7 @@ try { - userWhiteList.load(); + whitelist.load(); } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", userWhiteList.getFile().getName(), var6); -+ LOGGER.warn("Could not load existing file {}", userWhiteList.getFile().getName()); // CraftBukkit - don't print stacktrace +- LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName(), var6); ++ LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -317,6 +_,35 @@ - private void movePlayerFile(File file3, String oldFileName, String newFileName) { - File file4 = new File(worldPlayersDirectory, oldFileName + ".dat"); - File file5 = new File(file3, newFileName + ".dat"); + private void movePlayerFile(final File directory, final String oldName, final String newName) { + File oldFileName = new File(worldPlayerDirectory, oldName + ".dat"); + File newFileName = new File(directory, newName + ".dat"); + // CraftBukkit start - Use old file name to seed lastKnownName + net.minecraft.nbt.CompoundTag root = null; + + try { -+ root = net.minecraft.nbt.NbtIo.readCompressed(new java.io.FileInputStream(file4), net.minecraft.nbt.NbtAccounter.unlimitedHeap()); ++ root = net.minecraft.nbt.NbtIo.readCompressed(new java.io.FileInputStream(oldFileName), net.minecraft.nbt.NbtAccounter.unlimitedHeap()); + } catch (Exception exception) { + // Paper start + exception.printStackTrace(); @@ -67,10 +67,10 @@ + root.put("bukkit", new net.minecraft.nbt.CompoundTag()); + } + net.minecraft.nbt.CompoundTag data = root.getCompoundOrEmpty("bukkit"); -+ data.putString("lastKnownName", oldFileName); ++ data.putString("lastKnownName", oldName); + + try { -+ net.minecraft.nbt.NbtIo.writeCompressed(root, new java.io.FileOutputStream(file1)); ++ net.minecraft.nbt.NbtIo.writeCompressed(root, new java.io.FileOutputStream(oldFileName)); + } catch (Exception exception) { + // Paper start + exception.printStackTrace(); @@ -79,6 +79,6 @@ + } + } + // CraftBukkit end - OldUsersConverter.ensureDirectoryExists(file3); - if (!file4.renameTo(file5)) { - throw new OldUsersConverter.ConversionError("Could not convert file for " + oldFileName); + OldUsersConverter.ensureDirectoryExists(directory); + if (!oldFileName.renameTo(newFileName)) { + throw new OldUsersConverter.ConversionError("Could not convert file for " + oldName); diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index 7ba449bd2628..2ab42ad8acc2 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -20,7 +20,7 @@ public final PlayerDataStorage playerIo; private final LayeredRegistryAccess registries; private int viewDistance; -@@ -129,9 +_,17 @@ +@@ -129,12 +_,20 @@ private boolean allowCommandsForAllPlayers; private int sendAllPlayerInfoIn; @@ -30,7 +30,10 @@ + public @Nullable String collideRuleTeamName; // Paper - Configurable player collision + public PlayerList( - MinecraftServer server, LayeredRegistryAccess registries, PlayerDataStorage playerIo, NotificationService notificationService + final MinecraftServer server, + final LayeredRegistryAccess registries, + final PlayerDataStorage playerIo, + final NotificationService notificationService ) { + this.cserver = server.server = new org.bukkit.craftbukkit.CraftServer((net.minecraft.server.dedicated.DedicatedServer) server, this); + server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper @@ -38,63 +41,63 @@ this.server = server; this.registries = registries; this.playerIo = playerIo; -@@ -141,23 +_,19 @@ +@@ -144,23 +_,19 @@ this.ipBans = new IpBanList(IPBANLIST_FILE, notificationService); } + abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor + - public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie) { + public void placeNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) { + player.isRealPlayer = true; // Paper + player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed - NameAndId nameAndId = player.nameAndId(); - UserNameToIdResolver userNameToIdResolver = this.server.services().nameToIdCache(); - Optional optional = userNameToIdResolver.get(nameAndId.id()); - String string = optional.map(NameAndId::name).orElse(nameAndId.name()); -+ if (player.lastKnownName != null) { string = player.lastKnownName; player.lastKnownName = null; } // CraftBukkit - Better rename detection - userNameToIdResolver.add(nameAndId); - ServerLevel serverLevel = player.level(); - String loggableAddress = connection.getLoggableAddress(this.server.logIPs()); + NameAndId gameProfile = player.nameAndId(); + UserNameToIdResolver profileCache = this.server.services().nameToIdCache(); + Optional oldProfile = profileCache.get(gameProfile.id()); + String oldName = oldProfile.map(NameAndId::name).orElse(gameProfile.name()); ++ if (player.lastKnownName != null) { oldName = player.lastKnownName; player.lastKnownName = null; } // CraftBukkit - Better rename detection + profileCache.add(gameProfile); + ServerLevel level = player.level(); + String address = connection.getLoggableAddress(this.server.logIPs()); - LOGGER.info( - "{}[{}] logged in with entity id {} at ({}, {}, {})", - player.getPlainTextName(), -- loggableAddress, +- address, - player.getId(), - player.getX(), - player.getY(), - player.getZ() - ); - LevelData levelData = serverLevel.getLevelData(); - ServerGamePacketListenerImpl serverGamePacketListenerImpl = new ServerGamePacketListenerImpl(this.server, connection, player, cookie); + LevelData levelData = level.getLevelData(); + ServerGamePacketListenerImpl playerConnection = new ServerGamePacketListenerImpl(this.server, connection, player, cookie); connection.setupInboundProtocol( -@@ -175,8 +_,8 @@ +@@ -177,8 +_,8 @@ levelData.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), - this.getViewDistance(), - this.getSimulationDistance(), -+ io.papermc.paper.FeatureHooks.getViewDistance(serverLevel), // Paper - view distance -+ io.papermc.paper.FeatureHooks.getSimulationDistance(serverLevel), // Paper - simulation distance - flag1, - !flag, - flag2, -@@ -184,6 +_,7 @@ ++ io.papermc.paper.FeatureHooks.getViewDistance(level), // Paper - view distance ++ io.papermc.paper.FeatureHooks.getSimulationDistance(level), // Paper - simulation distance + reducedDebugInfo, + !immediateRespawn, + doLimitedCrafting, +@@ -186,6 +_,7 @@ this.server.enforceSecureProfile() ) ); + player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit - serverGamePacketListenerImpl.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); - serverGamePacketListenerImpl.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); - serverGamePacketListenerImpl.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot())); -@@ -203,24 +_,129 @@ - mutableComponent = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), string); + playerConnection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); + playerConnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); + playerConnection.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot())); +@@ -205,24 +_,129 @@ + component = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), oldName); } -- this.broadcastSystemMessage(mutableComponent.withStyle(ChatFormatting.YELLOW), false); +- this.broadcastSystemMessage(component.withStyle(ChatFormatting.YELLOW), false); + // CraftBukkit start -+ mutableComponent.withStyle(ChatFormatting.YELLOW); -+ Component joinMessage = mutableComponent; // Paper - Adventure - serverGamePacketListenerImpl.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); ++ component.withStyle(ChatFormatting.YELLOW); ++ Component joinMessage = component; // Paper - Adventure + playerConnection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); ServerStatus status = this.server.getStatus(); if (status != null && !cookie.transferred()) { player.sendServerStatus(status); @@ -109,8 +112,8 @@ + // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below + // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks + player.suppressTrackerForLogin = true; - this.sendLevelInfo(player, serverLevel); - serverLevel.addNewPlayer(player); + this.sendLevelInfo(player, level); + level.addNewPlayer(player); - this.server.getCustomBossEvents().onPlayerConnect(player); + this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below serverLevel.addPlayerJoin(player); + // Paper end - Fire PlayerJoinEvent when Player is actually ready @@ -121,7 +124,7 @@ + // Ensure that player inventory is populated with its viewer + player.containerMenu.transferTo(player.containerMenu, bukkitPlayer); + -+ org.bukkit.event.player.PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(bukkitPlayer, io.papermc.paper.adventure.PaperAdventure.asAdventure(mutableComponent)); // Paper - Adventure ++ org.bukkit.event.player.PlayerJoinEvent playerJoinEvent = new org.bukkit.event.player.PlayerJoinEvent(bukkitPlayer, io.papermc.paper.adventure.PaperAdventure.asAdventure(component)); // Paper - Adventure + this.cserver.getPluginManager().callEvent(playerJoinEvent); + + if (!player.connection.isAcceptingMessages()) { @@ -173,21 +176,21 @@ + + //player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn // Paper - THIS IS NOT NEEDED ANYMORE + -+ this.sendLevelInfo(player, serverLevel); ++ this.sendLevelInfo(player, level); + + // CraftBukkit start - Only add if the player wasn't moved in the event -+ if (player.level() == serverLevel && !serverLevel.players().contains(player)) { -+ serverLevel.addNewPlayer(player); ++ if (player.level() == level && !level.players().contains(player)) { ++ level.addNewPlayer(player); + this.server.getCustomBossEvents().onPlayerConnect(player); + } + -+ serverLevel = player.level(); // CraftBukkit - Update in case join event changed it ++ level = player.level(); // CraftBukkit - Update in case join event changed it + // CraftBukkit end this.sendActivePlayerEffects(player); + // Paper - move loading pearls / parent vehicle up player.initInventoryMenu(); this.server.notificationManager().playerJoined(player); - serverGamePacketListenerImpl.resumeFlushing(); + playerConnection.resumeFlushing(); + // Paper start - Configurable player collision; Add to collideRule team if needed + final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard(); + final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName); @@ -199,9 +202,9 @@ + LOGGER.info( + "{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", // CraftBukkit - add world name + player.getPlainTextName(), -+ loggableAddress, ++ address, + player.getId(), -+ serverLevel.serverLevelData.getLevelName(), // CraftBukkit - add world name ++ level.serverLevelData.getLevelName(), // CraftBukkit - add world name + player.getX(), + player.getY(), + player.getZ() @@ -209,18 +212,18 @@ + // CraftBukkit end - moved down + // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead + if (player.isDeadOrDying()) { -+ net.minecraft.core.Holder plains = serverLevel.registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME) ++ net.minecraft.core.Holder plains = level.registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME) + .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); + player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( -+ new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, player.chunkPosition(), plains), -+ serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null) ++ new net.minecraft.world.level.chunk.EmptyLevelChunk(level, player.chunkPosition(), plains), ++ level.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null) + ); + } + // Paper end - Send empty chunk } - public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) { -@@ -242,31 +_,40 @@ + public void updateEntireScoreboard(final ServerScoreboard scoreboard, final ServerPlayer player) { +@@ -244,6 +_,15 @@ } } @@ -235,64 +238,67 @@ + // Paper end - virtual world border API public void addWorldborderListener(final ServerLevel level) { level.getWorldBorder().addListener(new BorderChangeListener() { + { +@@ -252,27 +_,27 @@ + @Override - public void onSetSize(WorldBorder border, double size) { + public void onSetSize(final WorldBorder border, final double newSize) { - PlayerList.this.broadcastAll(new ClientboundSetBorderSizePacket(border), level.dimension()); + PlayerList.this.broadcastWorldborder(new ClientboundSetBorderSizePacket(border), level.dimension()); // Paper - virtual world border API } @Override - public void onLerpSize(WorldBorder border, double oldSize, double newSize, long time, long startTime) { + public void onLerpSize(final WorldBorder border, final double fromSize, final double targetSize, final long ticks, final long gameTime) { - PlayerList.this.broadcastAll(new ClientboundSetBorderLerpSizePacket(border), level.dimension()); + PlayerList.this.broadcastWorldborder(new ClientboundSetBorderLerpSizePacket(border), level.dimension()); // Paper - virtual world border API } @Override - public void onSetCenter(WorldBorder border, double x, double z) { + public void onSetCenter(final WorldBorder border, final double x, final double z) { - PlayerList.this.broadcastAll(new ClientboundSetBorderCenterPacket(border), level.dimension()); + PlayerList.this.broadcastWorldborder(new ClientboundSetBorderCenterPacket(border), level.dimension()); // Paper - virtual world border API } @Override - public void onSetWarningTime(WorldBorder border, int warningTime) { + public void onSetWarningTime(final WorldBorder border, final int time) { - PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDelayPacket(border), level.dimension()); + PlayerList.this.broadcastWorldborder(new ClientboundSetBorderWarningDelayPacket(border), level.dimension()); // Paper - virtual world border API } @Override - public void onSetWarningBlocks(WorldBorder border, int warningBlocks) { + public void onSetWarningBlocks(final WorldBorder border, final int blocks) { - PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDistancePacket(border), level.dimension()); + PlayerList.this.broadcastWorldborder(new ClientboundSetBorderWarningDistancePacket(border), level.dimension()); // Paper - virtual world border API } @Override -@@ -290,56 +_,137 @@ +@@ -296,64 +_,148 @@ } - protected void save(ServerPlayer player) { + protected void save(final ServerPlayer player) { + if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit this.playerIo.save(player); -- ServerStatsCounter serverStatsCounter = this.stats.get(player.getUUID()); -+ ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit - if (serverStatsCounter != null) { - serverStatsCounter.save(); +- ServerStatsCounter stats = this.stats.get(player.getUUID()); ++ ServerStatsCounter stats = player.getStats(); // CraftBukkit + if (stats != null) { + stats.save(); } -- PlayerAdvancements playerAdvancements = this.advancements.get(player.getUUID()); -+ PlayerAdvancements playerAdvancements = player.getAdvancements(); // CraftBukkit - if (playerAdvancements != null) { - playerAdvancements.save(); +- PlayerAdvancements advancements = this.advancements.get(player.getUUID()); ++ PlayerAdvancements advancements = player.getAdvancements(); // CraftBukkit + if (advancements != null) { + advancements.save(); } } -- public void remove(ServerPlayer player) { -+ public net.kyori.adventure.text.@Nullable Component remove(ServerPlayer player) { // CraftBukkit - return string // Paper - return Component +- public void remove(final ServerPlayer player) { ++ public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player) { // CraftBukkit - return string // Paper - return Component + // Paper start - Fix kick event leave message not being sent + return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName()))); + } -+ public net.kyori.adventure.text.@Nullable Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) { ++ public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player, final net.kyori.adventure.text.Component leaveMessage) { + // Paper end - Fix kick event leave message not being sent - ServerLevel serverLevel = player.level(); + ServerLevel level = player.level(); player.awardStat(Stats.LEAVE_GAME); + // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it + // See SPIGOT-5799, SPIGOT-6145 @@ -326,37 +332,37 @@ + // Paper end - Drop carried item when player has disconnected this.save(player); if (player.isPassenger()) { - Entity rootVehicle = player.getRootVehicle(); - if (rootVehicle.hasExactlyOnePlayerPassenger()) { + Entity vehicle = player.getRootVehicle(); + if (vehicle.hasExactlyOnePlayerPassenger()) { LOGGER.debug("Removing player mount"); player.stopRiding(); -- rootVehicle.getPassengersAndSelf().forEach(entity -> entity.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER)); -+ rootVehicle.getPassengersAndSelf().forEach(entity -> { +- vehicle.getPassengersAndSelf().forEach(e -> e.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER)); ++ vehicle.getPassengersAndSelf().forEach(e -> { + // Paper start - Fix villager boat exploit -+ if (entity instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) { ++ if (e instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) { + final net.minecraft.world.entity.player.Player human = villager.getTradingPlayer(); + if (human != null) { + villager.setTradingPlayer(null); + } + } + // Paper end - Fix villager boat exploit -+ entity.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause ++ e.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause + }); } } player.unRide(); - for (ThrownEnderpearl thrownEnderpearl : player.getEnderPearls()) { -- thrownEnderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER); + for (ThrownEnderpearl enderpearl : player.getEnderPearls()) { +- enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER); + // Paper start - Allow using old ender pearl behavior -+ if (!thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) { -+ thrownEnderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause ++ if (!enderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) { ++ enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause + } + // Paper end - Allow using old ender pearl behavior } - serverLevel.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER); + level.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER); + player.retireScheduler(); // Paper - Folia schedulers player.getAdvancements().stopListening(); this.players.remove(player); @@ -378,9 +384,9 @@ - this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID()))); - } - -- public @Nullable Component canPlayerLogin(SocketAddress socketAddress, NameAndId nameAndId) { +- public @Nullable Component canPlayerLogin(final SocketAddress address, final NameAndId nameAndId) { - if (this.bans.isBanned(nameAndId)) { -- UserBanListEntry userBanListEntry = this.bans.get(nameAndId); +- UserBanListEntry ban = this.bans.get(nameAndId); + // CraftBukkit start + // this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID()))); + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID())); @@ -408,36 +414,35 @@ + } + } + // Paper end - PlayerLoginEvent -+ public LoginResult canPlayerLogin(SocketAddress socketAddress, NameAndId nameAndId) { // Paper - PlayerLoginEvent ++ public LoginResult canPlayerLogin(final SocketAddress address, final NameAndId nameAndId) { // Paper - PlayerLoginEvent + LoginResult whitelistEventResult; // Paper + // Paper start - Fix MC-158900 -+ UserBanListEntry userBanListEntry; -+ if (this.bans.isBanned(nameAndId) && (userBanListEntry = this.bans.get(nameAndId)) != null) { ++ UserBanListEntry ban1; ++ if (this.bans.isBanned(nameAndId) && (ban1 = this.bans.get(nameAndId)) != null) { ++ UserBanListEntry ban = ban1; + // Paper end - Fix MC-158900 - MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned.reason", userBanListEntry.getReasonMessage()); - if (userBanListEntry.getExpires() != null) { - mutableComponent.append( -@@ -347,9 +_,11 @@ - ); + MutableComponent reason = Component.translatable("multiplayer.disconnect.banned.reason", ban.getReasonMessage()); + if (ban.getExpires() != null) { + reason.append(Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.format(ban.getExpires()))); } -- return mutableComponent; +- return reason; - } else if (!this.isWhiteListed(nameAndId)) { - return Component.translatable("multiplayer.disconnect.not_whitelisted"); -+ return new LoginResult(mutableComponent, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent ++ return new LoginResult(reason, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent + // Paper start - whitelist event + } else if ((whitelistEventResult = this.isWhiteListedLogin(nameAndId)).result == org.bukkit.event.player.PlayerLoginEvent.Result.KICK_WHITELIST) { + return whitelistEventResult; + // Paper end - } else if (this.ipBans.isBanned(socketAddress)) { - IpBanListEntry ipBanListEntry = this.ipBans.get(socketAddress); - MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipBanListEntry.getReasonMessage()); -@@ -359,19 +_,18 @@ - ); + } else if (this.ipBans.isBanned(address)) { + IpBanListEntry ban = this.ipBans.get(address); + MutableComponent reason = Component.translatable("multiplayer.disconnect.banned_ip.reason", ban.getReasonMessage()); +@@ -361,19 +_,18 @@ + reason.append(Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.format(ban.getExpires()))); } -- return mutableComponent; -+ return new LoginResult(mutableComponent, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent +- return reason; ++ return new LoginResult(reason, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent } else { - return this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId) - ? Component.translatable("multiplayer.disconnect.server_full") @@ -446,153 +451,153 @@ } } -- public boolean disconnectAllPlayersWithProfile(UUID profileId) { -+ public boolean disconnectAllPlayersWithProfile(GameProfile profile) { // Paper - validate usernames -+ UUID profileId = profile.id(); // Paper - validate usernames - Set set = Sets.newIdentityHashSet(); +- public boolean disconnectAllPlayersWithProfile(final UUID playerId) { ++ public boolean disconnectAllPlayersWithProfile(final GameProfile profile) { // Paper - validate usernames ++ UUID playerId = profile.id(); // Paper - validate usernames + Set dupes = Sets.newIdentityHashSet(); - for (ServerPlayer serverPlayer : this.players) { -- if (serverPlayer.getUUID().equals(profileId)) { -+ if (serverPlayer.getUUID().equals(profileId) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && serverPlayer.getGameProfile().name().equalsIgnoreCase(profile.name()))) { // Paper - validate usernames - set.add(serverPlayer); + for (ServerPlayer player : this.players) { +- if (player.getUUID().equals(playerId)) { ++ if (player.getUUID().equals(playerId) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && player.getGameProfile().name().equalsIgnoreCase(profile.name()))) { // Paper - validate usernames + dupes.add(player); } } -@@ -382,23 +_,31 @@ +@@ -384,23 +_,31 @@ } - for (ServerPlayer serverPlayer2 : set) { -- serverPlayer2.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE); -+ serverPlayer2.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE, io.papermc.paper.connection.DisconnectionReason.DUPLICATE_LOGIN_MESSAGE); // Paper - disconnect API + for (ServerPlayer playerx : dupes) { +- playerx.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE); ++ playerx.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE, io.papermc.paper.connection.DisconnectionReason.DUPLICATE_LOGIN_MESSAGE); // Paper - disconnect API } - return !set.isEmpty(); + return !dupes.isEmpty(); } -- public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason) { -- TeleportTransition teleportTransition = player.findRespawnPositionAndUseSpawnBlock(!keepInventory, TeleportTransition.DO_NOTHING); +- public ServerPlayer respawn(final ServerPlayer serverPlayer, final boolean keepAllPlayerData, final Entity.RemovalReason removalReason) { +- TeleportTransition respawnInfo = serverPlayer.findRespawnPositionAndUseSpawnBlock(!keepAllPlayerData, TeleportTransition.DO_NOTHING); + // Paper start - respawn event -+ public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason) { -+ ServerPlayer.RespawnResult result = player.findRespawnPositionAndUseSpawnBlock0(!keepInventory, TeleportTransition.DO_NOTHING, respawnReason); ++ public ServerPlayer respawn(final ServerPlayer serverPlayer, final boolean keepAllPlayerData, final Entity.RemovalReason removalReason, final org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason) { ++ ServerPlayer.RespawnResult result = serverPlayer.findRespawnPositionAndUseSpawnBlock0(!keepAllPlayerData, TeleportTransition.DO_NOTHING, respawnReason); + if (result == null) { // disconnected player during the respawn event -+ return player; ++ return serverPlayer; + } -+ TeleportTransition teleportTransition = result.transition(); -+ Level fromLevel = player.level(); ++ TeleportTransition respawnInfo = result.transition(); ++ Level fromLevel = serverPlayer.level(); + // Paper end - respawn event - this.players.remove(player); -+ this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Paper - player.level().removePlayerImmediately(player, reason); - ServerLevel level = teleportTransition.newLevel(); -- ServerPlayer serverPlayer = new ServerPlayer(this.server, level, player.getGameProfile(), player.clientInformation()); -+ ServerPlayer serverPlayer = player; // Paper - TODO - recreate instance - serverPlayer.connection = player.connection; - serverPlayer.restoreFrom(player, keepInventory); - serverPlayer.setId(player.getId()); - serverPlayer.setMainArm(player.getMainArm()); -- if (!teleportTransition.missingRespawnBlock()) { -+ if (false && !teleportTransition.missingRespawnBlock()) { // Paper - Once we not reuse the player entity, this can be flipped again but without the events being fired - serverPlayer.copyRespawnPosition(player); + this.players.remove(serverPlayer); ++ this.playersByName.remove(serverPlayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Paper + serverPlayer.level().removePlayerImmediately(serverPlayer, removalReason); + ServerLevel level = respawnInfo.newLevel(); +- ServerPlayer player = new ServerPlayer(this.server, level, serverPlayer.getGameProfile(), serverPlayer.clientInformation()); ++ ServerPlayer player = serverPlayer; // Paper - TODO - recreate instance + player.connection = serverPlayer.connection; + player.restoreFrom(serverPlayer, keepAllPlayerData); + player.setId(serverPlayer.getId()); + player.setMainArm(serverPlayer.getMainArm()); +- if (!respawnInfo.missingRespawnBlock()) { ++ if (false && !respawnInfo.missingRespawnBlock()) { // Paper - Once we not reuse the player entity, this can be flipped again but without the events being fired + player.copyRespawnPosition(serverPlayer); } -@@ -406,17 +_,26 @@ - serverPlayer.addTag(string); +@@ -408,17 +_,26 @@ + player.addTag(tag); } + // Paper start - Once we not reuse the player entity we can remove this. -+ if (!keepInventory) player.reset(); -+ serverPlayer.spawnIn(level); -+ serverPlayer.unsetRemoved(); -+ serverPlayer.setShiftKeyDown(false); ++ if (!keepAllPlayerData) serverPlayer.reset(); ++ player.spawnIn(level); ++ player.unsetRemoved(); ++ player.setShiftKeyDown(false); + // Paper end - Vec3 vec3 = teleportTransition.position(); - serverPlayer.snapTo(vec3.x, vec3.y, vec3.z, teleportTransition.yRot(), teleportTransition.xRot()); -+ serverPlayer.connection.resetPosition(); // Paper - Fix SPIGOT-1903, MC-98153 -+ level.getChunkSource().addTicketWithRadius(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(net.minecraft.util.Mth.floor(vec3.x()) >> 4, net.minecraft.util.Mth.floor(vec3.z()) >> 4), 1); // Paper - post teleport ticket type - if (teleportTransition.missingRespawnBlock()) { - serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); -+ serverPlayer.setRespawnPosition(null, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed + Vec3 pos = respawnInfo.position(); + player.snapTo(pos.x, pos.y, pos.z, respawnInfo.yRot(), respawnInfo.xRot()); ++ player.connection.resetPosition(); // Paper - Fix SPIGOT-1903, MC-98153 ++ level.getChunkSource().addTicketWithRadius(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(net.minecraft.util.Mth.floor(pos.x()) >> 4, net.minecraft.util.Mth.floor(pos.z()) >> 4), 1); // Paper - post teleport ticket type + if (respawnInfo.missingRespawnBlock()) { + player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F)); ++ player.setRespawnPosition(null, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed } - byte b = keepInventory ? ClientboundRespawnPacket.KEEP_ATTRIBUTE_MODIFIERS : 0; - ServerLevel serverLevel = serverPlayer.level(); - LevelData levelData = serverLevel.getLevelData(); - serverPlayer.connection.send(new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(serverLevel), b)); -- serverPlayer.connection.teleport(serverPlayer.getX(), serverPlayer.getY(), serverPlayer.getZ(), serverPlayer.getYRot(), serverPlayer.getXRot()); -+ serverPlayer.connection.internalTeleport(serverPlayer.getX(), serverPlayer.getY(), serverPlayer.getZ(), serverPlayer.getYRot(), serverPlayer.getXRot()); // Paper - serverPlayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData())); - serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); - serverPlayer.connection -@@ -426,9 +_,15 @@ - this.sendPlayerPermissionLevel(serverPlayer); - level.addRespawnedPlayer(serverPlayer); - this.players.add(serverPlayer); -+ this.playersByName.put(serverPlayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT), serverPlayer); // Paper - this.playersByUUID.put(serverPlayer.getUUID(), serverPlayer); - serverPlayer.initInventoryMenu(); - serverPlayer.setHealth(serverPlayer.getHealth()); + byte dataToKeep = keepAllPlayerData ? ClientboundRespawnPacket.KEEP_ATTRIBUTE_MODIFIERS : 0; + ServerLevel playerLevel = player.level(); + LevelData levelData = playerLevel.getLevelData(); + player.connection.send(new ClientboundRespawnPacket(player.createCommonSpawnInfo(playerLevel), dataToKeep)); +- player.connection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); ++ player.connection.internalTeleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); // Paper + player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData())); + player.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); + player.connection.send(new ClientboundSetExperiencePacket(player.experienceProgress, player.totalExperience, player.experienceLevel)); +@@ -427,9 +_,15 @@ + this.sendPlayerPermissionLevel(player); + level.addRespawnedPlayer(player); + this.players.add(player); ++ this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Paper + this.playersByUUID.put(player.getUUID(), player); + player.initInventoryMenu(); + player.setHealth(player.getHealth()); + // Paper start - Once we not reuse the player entity we can remove this. + // But we have to resend the player info as it's not marked as dirty -+ this.sendAllPlayerInfo(player); // Update health -+ player.onUpdateAbilities(); // Update inventory, etc ++ this.sendAllPlayerInfo(serverPlayer); // Update health ++ serverPlayer.onUpdateAbilities(); // Update inventory, etc + // Paper end - ServerPlayer.RespawnConfig respawnConfig = serverPlayer.getRespawnConfig(); - if (!keepInventory && respawnConfig != null) { + ServerPlayer.RespawnConfig respawnConfig = player.getRespawnConfig(); + if (!keepAllPlayerData && respawnConfig != null) { LevelData.RespawnData respawnData = respawnConfig.respawnData(); -@@ -454,6 +_,29 @@ +@@ -455,6 +_,29 @@ } } + // Paper start + // Save player file again if they were disconnected -+ if (serverPlayer.connection.isDisconnected()) { -+ this.save(serverPlayer); ++ if (player.connection.isDisconnected()) { ++ this.save(player); + } + + // It's possible for respawn to be in a diff dimension + if (fromLevel != level) { -+ new org.bukkit.event.player.PlayerChangedWorldEvent(serverPlayer.getBukkitEntity(), fromLevel.getWorld()).callEvent(); -+ serverPlayer.triggerDimensionChangeTriggers(level); ++ new org.bukkit.event.player.PlayerChangedWorldEvent(player.getBukkitEntity(), fromLevel.getWorld()).callEvent(); ++ player.triggerDimensionChangeTriggers(level); + } + + // Call post respawn event + new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent( -+ serverPlayer.getBukkitEntity(), -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(teleportTransition.position(), level, teleportTransition.yRot(), teleportTransition.xRot()), ++ player.getBukkitEntity(), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(respawnInfo.position(), level, respawnInfo.yRot(), respawnInfo.xRot()), + result.isBedSpawn(), + result.isAnchorSpawn(), -+ teleportTransition.missingRespawnBlock(), ++ respawnInfo.missingRespawnBlock(), + respawnReason + ).callEvent(); + // Paper end + - return serverPlayer; + return player; } -@@ -462,23 +_,58 @@ +@@ -463,23 +_,58 @@ } - public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl connection) { + public void sendActiveEffects(final LivingEntity livingEntity, final ServerGamePacketListenerImpl connection) { + // Paper start - collect packets -+ this.sendActiveEffects(entity, connection::send); ++ this.sendActiveEffects(livingEntity, connection::send); + } -+ public void sendActiveEffects(LivingEntity entity, java.util.function.Consumer> packetConsumer) { ++ public void sendActiveEffects(final LivingEntity livingEntity, final java.util.function.Consumer> packetConsumer) { + // Paper end - collect packets - for (MobEffectInstance mobEffectInstance : entity.getActiveEffects()) { -- connection.send(new ClientboundUpdateMobEffectPacket(entity.getId(), mobEffectInstance, false)); -+ packetConsumer.accept(new ClientboundUpdateMobEffectPacket(entity.getId(), mobEffectInstance, false)); // Paper - collect packets + for (MobEffectInstance effect : livingEntity.getActiveEffects()) { +- connection.send(new ClientboundUpdateMobEffectPacket(livingEntity.getId(), effect, false)); ++ packetConsumer.accept(new ClientboundUpdateMobEffectPacket(livingEntity.getId(), effect, false)); // Paper - collect packets } } - public void sendPlayerPermissionLevel(ServerPlayer player) { + public void sendPlayerPermissionLevel(final ServerPlayer player) { + // Paper start - avoid recalculating permissions if possible + this.sendPlayerPermissionLevel(player, true); + } + -+ public void sendPlayerPermissionLevel(ServerPlayer player, boolean recalculatePermissions) { ++ public void sendPlayerPermissionLevel(final ServerPlayer player, final boolean recalculatePermissions) { + // Paper end - avoid recalculating permissions if possible - LevelBasedPermissionSet profilePermissions = this.server.getProfilePermissions(player.nameAndId()); -- this.sendPlayerPermissionLevel(player, profilePermissions); -+ this.sendPlayerPermissionLevel(player, profilePermissions, recalculatePermissions); // Paper - avoid recalculating permissions if possible + LevelBasedPermissionSet permissions = this.server.getProfilePermissions(player.nameAndId()); +- this.sendPlayerPermissionLevel(player, permissions); ++ this.sendPlayerPermissionLevel(player, permissions, recalculatePermissions); // Paper - avoid recalculating permissions if possible } public void tick() { @@ -627,24 +632,24 @@ + } + // CraftBukkit end + - public void broadcastAll(Packet packet) { - for (ServerPlayer serverPlayer : this.players) { - serverPlayer.connection.send(packet); -@@ -564,6 +_,12 @@ + public void broadcastAll(final Packet packet) { + for (ServerPlayer player : this.players) { + player.connection.send(packet); +@@ -565,6 +_,12 @@ } - private void sendPlayerPermissionLevel(ServerPlayer player, LevelBasedPermissionSet permissions) { + private void sendPlayerPermissionLevel(final ServerPlayer player, final LevelBasedPermissionSet permissions) { + // Paper start - Add sendOpLevel API + this.sendPlayerPermissionLevel(player, permissions, true); + } + -+ public void sendPlayerPermissionLevel(ServerPlayer player, LevelBasedPermissionSet permissions, boolean recalculatePermissions) { ++ public void sendPlayerPermissionLevel(final ServerPlayer player, final LevelBasedPermissionSet permissions, final boolean recalculatePermissions) { + // Paper end - Add sendOpLevel API if (player.connection != null) { - byte b = switch (permissions.level()) { + byte eventId = switch (permissions.level()) { case ALL -> EntityEvent.PERMISSION_LEVEL_ALL; -@@ -575,9 +_,48 @@ - player.connection.send(new ClientboundEntityEventPacket(player, b)); +@@ -576,9 +_,48 @@ + player.connection.send(new ClientboundEntityEventPacket(player, eventId)); } + if (recalculatePermissions) { // Paper - Add sendOpLevel API @@ -691,38 +696,40 @@ + // Paper end + + @io.papermc.paper.annotation.DoNotUse // Paper - public boolean isWhiteListed(NameAndId nameAndId) { + public boolean isWhiteListed(final NameAndId nameAndId) { return !this.isUsingWhitelist() || this.ops.contains(nameAndId) || this.whitelist.contains(nameAndId); } -@@ -589,21 +_,17 @@ +@@ -590,16 +_,7 @@ } - public @Nullable ServerPlayer getPlayerByName(String username) { + public @Nullable ServerPlayer getPlayerByName(final String name) { - int size = this.players.size(); - - for (int i = 0; i < size; i++) { -- ServerPlayer serverPlayer = this.players.get(i); -- if (serverPlayer.getGameProfile().name().equalsIgnoreCase(username)) { -- return serverPlayer; +- ServerPlayer player = this.players.get(i); +- if (player.getGameProfile().name().equalsIgnoreCase(name)) { +- return player; - } - } - - return null; -+ return this.playersByName.get(username.toLowerCase(java.util.Locale.ROOT)); // Spigot ++ return this.playersByName.get(name.toLowerCase(java.util.Locale.ROOT)); // Spigot } - public void broadcast(@Nullable Player except, double x, double y, double z, double radius, ResourceKey dimension, Packet packet) { + public void broadcast( +@@ -613,6 +_,11 @@ + ) { for (int i = 0; i < this.players.size(); i++) { - ServerPlayer serverPlayer = this.players.get(i); + ServerPlayer player = this.players.get(i); + // CraftBukkit start - Test if player receiving packet can see the source of the packet -+ if (except != null && !serverPlayer.getBukkitEntity().canSee(except.getBukkitEntity())) { ++ if (except != null && !player.getBukkitEntity().canSee(except.getBukkitEntity())) { + continue; + } + // CraftBukkit end - if (serverPlayer != except && serverPlayer.level().dimension() == dimension) { - double d = x - serverPlayer.getX(); - double d1 = y - serverPlayer.getY(); -@@ -616,9 +_,11 @@ + if (player != except && player.level().dimension() == dimension) { + double xd = x - player.getX(); + double yd = y - player.getY(); +@@ -625,9 +_,11 @@ } public void saveAll() { @@ -734,9 +741,9 @@ } public UserWhiteList getWhiteList() { -@@ -645,10 +_,18 @@ +@@ -654,10 +_,18 @@ player.connection.send(new ClientboundInitializeBorderPacket(worldBorder)); - player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().get(GameRules.ADVANCE_TIME))); + player.connection.send(this.server.clockManager().createFullSyncPacket()); player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData())); + // Paper start - view distances + player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level))); @@ -756,9 +763,9 @@ } player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F)); -@@ -657,8 +_,21 @@ +@@ -666,8 +_,21 @@ - public void sendAllPlayerInfo(ServerPlayer player) { + public void sendAllPlayerInfo(final ServerPlayer player) { player.inventoryMenu.sendAllDataToRemote(); - player.resetSentInfo(); + // entityplayer.resetSentInfo(); @@ -779,7 +786,7 @@ } public int getPlayerCount() { -@@ -706,9 +_,26 @@ +@@ -711,9 +_,26 @@ } public void removeAll() { @@ -808,59 +815,59 @@ + // Paper end - Configurable player collision } - public void broadcastSystemMessage(Component message, boolean overlay) { -@@ -731,20 +_,39 @@ + public void broadcastSystemMessage(final Component message, final boolean overlay) { +@@ -736,20 +_,39 @@ } - public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound boundChatType) { -- this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, boundChatType); + public void broadcastChatMessage(final PlayerChatMessage message, final ServerPlayer sender, final ChatType.Bound chatType) { +- this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, chatType); + // Paper start -+ this.broadcastChatMessage(message, sender, boundChatType, null); ++ this.broadcastChatMessage(message, sender, chatType, null); + } -+ public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound boundChatType, @Nullable Function unsignedFunction) { ++ public void broadcastChatMessage(final PlayerChatMessage message, final ServerPlayer sender, final ChatType.Bound chatType, final @Nullable Function unsignedFunction) { + // Paper end -+ this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, boundChatType, unsignedFunction); // Paper ++ this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, chatType, unsignedFunction); // Paper } private void broadcastChatMessage( - PlayerChatMessage message, Predicate shouldFilterMessageTo, @Nullable ServerPlayer sender, ChatType.Bound boundChatType + final PlayerChatMessage message, final Predicate isFiltered, final @Nullable ServerPlayer senderPlayer, final ChatType.Bound chatType ) { + // Paper start -+ this.broadcastChatMessage(message, shouldFilterMessageTo, sender, boundChatType, null); ++ this.broadcastChatMessage(message, isFiltered, senderPlayer, chatType, null); + } -+ public void broadcastChatMessage(PlayerChatMessage message, Predicate shouldFilterMessageTo, @Nullable ServerPlayer sender, ChatType.Bound boundChatType, @Nullable Function unsignedFunction) { ++ public void broadcastChatMessage(final PlayerChatMessage message, final Predicate isFiltered, final @Nullable ServerPlayer senderPlayer, final ChatType.Bound chatType, final @Nullable Function unsignedFunction) { + // Paper end - boolean flag = this.verifyChatTrusted(message); -- this.server.logChatMessage(message.decoratedContent(), boundChatType, flag ? null : "Not Secure"); -+ this.server.logChatMessage((unsignedFunction == null ? message.decoratedContent() : unsignedFunction.apply(this.server.console)), boundChatType, flag ? null : "Not Secure"); // Paper - OutgoingChatMessage outgoingChatMessage = OutgoingChatMessage.create(message); - boolean flag1 = false; - -+ Packet disguised = sender != null && unsignedFunction == null ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(outgoingChatMessage.content(), boundChatType) : null; // Paper - don't send player chat packets from vanished players - for (ServerPlayer serverPlayer : this.players) { - boolean flag2 = shouldFilterMessageTo.test(serverPlayer); -- serverPlayer.sendChatMessage(outgoingChatMessage, flag2, boundChatType); + boolean trusted = this.verifyChatTrusted(message); +- this.server.logChatMessage(message.decoratedContent(), chatType, trusted ? null : "Not Secure"); ++ this.server.logChatMessage((unsignedFunction == null ? message.decoratedContent() : unsignedFunction.apply(this.server.console)), chatType, trusted ? null : "Not Secure"); // Paper + OutgoingChatMessage tracked = OutgoingChatMessage.create(message); + boolean wasFullyFiltered = false; + ++ Packet disguised = senderPlayer != null && unsignedFunction == null ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(tracked.content(), chatType) : null; // Paper - don't send player chat packets from vanished players + for (ServerPlayer player : this.players) { + boolean filtered = isFiltered.test(player); +- player.sendChatMessage(tracked, filtered, chatType); + // Paper start - don't send player chat packets from vanished players -+ if (sender != null && !serverPlayer.getBukkitEntity().canSee(sender.getBukkitEntity())) { -+ serverPlayer.connection.send(unsignedFunction != null -+ ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(unsignedFunction.apply(serverPlayer.getBukkitEntity()), boundChatType) ++ if (senderPlayer != null && !player.getBukkitEntity().canSee(senderPlayer.getBukkitEntity())) { ++ player.connection.send(unsignedFunction != null ++ ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(unsignedFunction.apply(player.getBukkitEntity()), chatType) + : disguised); + continue; + } -+ serverPlayer.sendChatMessage(outgoingChatMessage, flag2, boundChatType, unsignedFunction == null ? null : unsignedFunction.apply(serverPlayer.getBukkitEntity())); ++ player.sendChatMessage(tracked, filtered, chatType, unsignedFunction == null ? null : unsignedFunction.apply(player.getBukkitEntity())); + // Paper end - flag1 |= flag2 && message.isFullyFiltered(); + wasFullyFiltered |= filtered && message.isFullyFiltered(); } -@@ -757,13 +_,21 @@ +@@ -762,13 +_,21 @@ return message.hasSignature() && !message.hasExpiredServer(Instant.now()); } -- public ServerStatsCounter getPlayerStats(Player player) { +- public ServerStatsCounter getPlayerStats(final Player player) { + // CraftBukkit start -+ public ServerStatsCounter getPlayerStats(ServerPlayer player) { ++ public ServerStatsCounter getPlayerStats(final ServerPlayer player) { GameProfile gameProfile = player.getGameProfile(); -- return this.stats.computeIfAbsent(gameProfile.id(), uuid -> { +- return this.stats.computeIfAbsent(gameProfile.id(), id -> { + ServerStatsCounter playerStatsCounter = player.getStats(); + if (playerStatsCounter == null) { + return this.getPlayerStats(gameProfile); @@ -868,35 +875,35 @@ + return playerStatsCounter; + } + } -+ public ServerStatsCounter getPlayerStats(GameProfile gameProfile) { - Path path = this.locateStatsFile(gameProfile); - return new ServerStatsCounter(this.server, path); ++ public ServerStatsCounter getPlayerStats(final GameProfile gameProfile) { + Path targetFile = this.locateStatsFile(gameProfile); + return new ServerStatsCounter(this.server, targetFile); - }); } + // CraftBukkit end - private Path locateStatsFile(GameProfile profile) { - Path worldPath = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR); -@@ -790,11 +_,11 @@ + private Path locateStatsFile(final GameProfile gameProfile) { + Path statFolder = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR); +@@ -795,11 +_,11 @@ - public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) { + public PlayerAdvancements getPlayerAdvancements(final ServerPlayer player) { UUID uuid = player.getUUID(); -- PlayerAdvancements playerAdvancements = this.advancements.get(uuid); -+ PlayerAdvancements playerAdvancements = player.getAdvancements(); // CraftBukkit - if (playerAdvancements == null) { - Path path = this.server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).resolve(uuid + ".json"); - playerAdvancements = new PlayerAdvancements(this.server.getFixerUpper(), this, this.server.getAdvancements(), path, player); -- this.advancements.put(uuid, playerAdvancements); -+ // this.advancements.put(uuid, playerAdvancements); // CraftBukkit +- PlayerAdvancements result = this.advancements.get(uuid); ++ PlayerAdvancements result = player.getAdvancements(); // CraftBukkit + if (result == null) { + Path uuidStatsFile = this.server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).resolve(uuid + ".json"); + result = new PlayerAdvancements(this.server.getFixerUpper(), this, this.server.getAdvancements(), uuidStatsFile, player); +- this.advancements.put(uuid, result); ++ // this.advancements.put(uuid, result); // CraftBukkit } - playerAdvancements.setPlayer(player); -@@ -842,11 +_,34 @@ + result.setPlayer(player); +@@ -847,11 +_,34 @@ } public void reloadResources() { -- for (PlayerAdvancements playerAdvancements : this.advancements.values()) { -- playerAdvancements.reload(this.server.getAdvancements()); +- for (PlayerAdvancements advancements : this.advancements.values()) { +- advancements.reload(this.server.getAdvancements()); + // Paper start - API for updating recipes on clients + this.reloadAdvancementData(); + this.reloadTagData(); @@ -926,5 +933,5 @@ + public void reloadRecipes() { + // CraftBukkit end RecipeManager recipeManager = this.server.getRecipeManager(); - ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket = new ClientboundUpdateRecipesPacket( + ClientboundUpdateRecipesPacket recipes = new ClientboundUpdateRecipesPacket( recipeManager.getSynchronizedItemProperties(), recipeManager.getSynchronizedStonecutterRecipes() diff --git a/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch b/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch index c5ba1378ddf3..0ea61aa2ca67 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/server/players/ProfileResolver.java +++ b/net/minecraft/server/players/ProfileResolver.java -@@ -25,7 +_,7 @@ +@@ -26,7 +_,7 @@ private final LoadingCache> profileCacheByName; - final LoadingCache> profileCacheById; + private final LoadingCache> profileCacheById; -- public Cached(final MinecraftSessionService sessionService, final UserNameToIdResolver resolver) { -+ public Cached(final MinecraftSessionService sessionService, final UserNameToIdResolver resolver, final io.papermc.paper.profile.PaperFilledProfileCache paperCache) { // Paper - add paperCache +- public Cached(final MinecraftSessionService sessionService, final UserNameToIdResolver nameToIdCache) { ++ public Cached(final MinecraftSessionService sessionService, final UserNameToIdResolver nameToIdCache, final io.papermc.paper.profile.PaperFilledProfileCache paperCache) { // Paper - add paperCache this.profileCacheById = CacheBuilder.newBuilder() .expireAfterAccess(Duration.ofMinutes(10L)) .maximumSize(256L) -@@ -33,7 +_,13 @@ +@@ -38,7 +_,13 @@ @Override - public Optional load(UUID id) { - ProfileResult profileResult = sessionService.fetchProfile(id, true); -- return Optional.ofNullable(profileResult).map(ProfileResult::profile); + public Optional load(final UUID profileId) { + ProfileResult result = sessionService.fetchProfile(profileId, true); +- return Optional.ofNullable(result).map(ProfileResult::profile); + // Paper start - update paper cache -+ return Optional.ofNullable(profileResult).map(ProfileResult::profile) ++ return Optional.ofNullable(result).map(ProfileResult::profile) + .map(profile -> { + paperCache.add(profile); + return profile; diff --git a/paper-server/patches/sources/net/minecraft/server/players/SleepStatus.java.patch b/paper-server/patches/sources/net/minecraft/server/players/SleepStatus.java.patch index feab2a62643e..b8a4adbbbc4c 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/SleepStatus.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/SleepStatus.java.patch @@ -3,39 +3,39 @@ @@ -14,8 +_,11 @@ } - public boolean areEnoughDeepSleeping(int requiredSleepPercentage, List sleepingPlayers) { -- int i = (int)sleepingPlayers.stream().filter(Player::isSleepingLongEnough).count(); -- return i >= this.sleepersNeeded(requiredSleepPercentage); + public boolean areEnoughDeepSleeping(final int sleepPercentageNeeded, final List players) { +- int deepSleepers = (int)players.stream().filter(Player::isSleepingLongEnough).count(); +- return deepSleepers >= this.sleepersNeeded(sleepPercentageNeeded); + // CraftBukkit start -+ int i = (int) sleepingPlayers.stream().filter(player -> player.isSleepingLongEnough() || player.fauxSleeping).count(); -+ boolean anyDeepSleep = sleepingPlayers.stream().anyMatch(Player::isSleepingLongEnough); -+ return anyDeepSleep && i >= this.sleepersNeeded(requiredSleepPercentage); ++ int deepSleepers = (int)players.stream().filter(player -> player.isSleepingLongEnough() || player.fauxSleeping).count(); ++ boolean anyDeepSleep = players.stream().anyMatch(Player::isSleepingLongEnough); ++ return anyDeepSleep && deepSleepers >= this.sleepersNeeded(sleepPercentageNeeded); + // CraftBukkit end } - public int sleepersNeeded(int requiredSleepPercentage) { + public int sleepersNeeded(final int sleepPercentageNeeded) { @@ -35,16 +_,22 @@ - int i1 = this.sleepingPlayers; + int oldSleepingPlayers = this.sleepingPlayers; this.activePlayers = 0; this.sleepingPlayers = 0; + boolean anySleep = false; // CraftBukkit - for (ServerPlayer serverPlayer : players) { - if (!serverPlayer.isSpectator()) { + for (ServerPlayer player : players) { + if (!player.isSpectator()) { this.activePlayers++; -- if (serverPlayer.isSleeping()) { -+ if (serverPlayer.isSleeping() || serverPlayer.fauxSleeping) { // CraftBukkit +- if (player.isSleeping()) { ++ if (player.isSleeping() || player.fauxSleeping) { // CraftBukkit this.sleepingPlayers++; } + // CraftBukkit start -+ if (serverPlayer.isSleeping()) { ++ if (player.isSleeping()) { + anySleep = true; + } + // CraftBukkit end } } -- return (i1 > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || i1 != this.sleepingPlayers); -+ return anySleep && (i1 > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || i1 != this.sleepingPlayers); // CraftBukkit +- return (oldSleepingPlayers > 0 || this.sleepingPlayers > 0) && (oldActivePlayers != this.activePlayers || oldSleepingPlayers != this.sleepingPlayers); ++ return anySleep && (oldSleepingPlayers > 0 || this.sleepingPlayers > 0) && (oldActivePlayers != this.activePlayers || oldSleepingPlayers != this.sleepingPlayers); // CraftBukkit } } diff --git a/paper-server/patches/sources/net/minecraft/server/players/StoredUserList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/StoredUserList.java.patch index b0d0b8a25fb1..ebcb9f5da52c 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/StoredUserList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/StoredUserList.java.patch @@ -8,11 +8,11 @@ + private final Map map = Maps.newConcurrentMap(); // Paper - Use ConcurrentHashMap in StoredUserList protected final NotificationService notificationService; - public StoredUserList(File file, NotificationService notificationService) { + public StoredUserList(final File file, final NotificationService notificationService) { @@ -59,8 +_,11 @@ } - public @Nullable V get(K user) { + public @Nullable V get(final K user) { - this.removeExpired(); - return this.map.get(this.getKeyForUser(user)); + // Paper start - Use ConcurrentHashMap in StoredUserList @@ -22,41 +22,44 @@ + // Paper end - Use ConcurrentHashMap in StoredUserList } - public boolean remove(K user) { -@@ -105,21 +_,12 @@ + public boolean remove(final K user) { +@@ -105,22 +_,15 @@ } - protected boolean contains(K entry) { + protected boolean contains(final K user) { + this.removeExpired(); // CraftBukkit - SPIGOT-7589: Consistently remove expired entries to mirror .get(...) - return this.map.containsKey(this.getKeyForUser(entry)); + return this.map.containsKey(this.getKeyForUser(user)); } ++ // Paper start - Use ConcurrentHashMap in StoredUserList private void removeExpired() { -- List list = Lists.newArrayList(); +- List toRemove = Lists.newArrayList(); - -- for (V storedUserEntry : this.map.values()) { -- if (storedUserEntry.hasExpired()) { -- list.add(storedUserEntry.getUser()); +- for (V entry : this.map.values()) { +- if (entry.hasExpired()) { +- toRemove.add(entry.getUser()); - } - } - -- for (K object : list) { -- this.map.remove(this.getKeyForUser(object)); +- for (K user : toRemove) { +- this.map.remove(this.getKeyForUser(user)); - } -+ this.map.values().removeIf(StoredUserEntry::hasExpired); // Paper - Use ConcurrentHashMap in StoredUserList ++ this.map.values().removeIf(StoredUserEntry::hasExpired); } ++ // Paper end - Use ConcurrentHashMap in StoredUserList + + protected abstract StoredUserEntry createEntry(final JsonObject object); - protected abstract StoredUserEntry createEntry(JsonObject entryData); @@ -129,6 +_,7 @@ } public void save() throws IOException { + this.removeExpired(); // Paper - remove expired values before saving - JsonArray jsonArray = new JsonArray(); - this.map.values().stream().map(storedEntry -> Util.make(new JsonObject(), storedEntry::serialize)).forEach(jsonArray::add); + JsonArray result = new JsonArray(); + this.map.values().stream().map(entry -> Util.make(new JsonObject(), entry::serialize)).forEach(result::add); @@ -153,7 +_,14 @@ - this.map.put(this.getKeyForUser(storedUserEntry.getUser()), (V)storedUserEntry); + this.map.put(this.getKeyForUser(entry.getUser()), (V)entry); } } + // Spigot start diff --git a/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch b/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch index c4ab728e1369..ff61eda61ae4 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/server/players/UserBanListEntry.java +++ b/net/minecraft/server/players/UserBanListEntry.java -@@ -17,7 +_,7 @@ +@@ -23,7 +_,7 @@ } - public UserBanListEntry(JsonObject entryData) { -- super(NameAndId.fromJson(entryData), entryData); -+ super(parseNameAndId(entryData), entryData); + public UserBanListEntry(final JsonObject object) { +- super(NameAndId.fromJson(object), object); ++ super(parseNameAndId(object), object); } @Override -@@ -33,4 +_,31 @@ - NameAndId nameAndId = this.getUser(); - return (Component)(nameAndId != null ? Component.literal(nameAndId.name()) : MESSAGE_UNKNOWN_USER); +@@ -39,4 +_,31 @@ + NameAndId user = this.getUser(); + return (Component)(user != null ? Component.literal(user.name()) : MESSAGE_UNKNOWN_USER); } + + // Spigot start diff --git a/paper-server/patches/sources/net/minecraft/server/players/UserNameToIdResolver.java.patch b/paper-server/patches/sources/net/minecraft/server/players/UserNameToIdResolver.java.patch index f19c3d3da1c0..1337cc1401bd 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/UserNameToIdResolver.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/UserNameToIdResolver.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/players/UserNameToIdResolver.java +++ b/net/minecraft/server/players/UserNameToIdResolver.java @@ -13,4 +_,8 @@ - void resolveOfflineUsers(boolean resolveOfflineUsers); + void resolveOfflineUsers(boolean value); void save(); + + void save(boolean async); // Paper + -+ @javax.annotation.Nullable NameAndId getIfCached(String name); // Paper ++ @org.jspecify.annotations.Nullable NameAndId getIfCached(String name); // Paper } diff --git a/paper-server/patches/sources/net/minecraft/server/players/UserWhiteList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/UserWhiteList.java.patch index 5351b2790cf6..4b5b7e7d5f62 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/UserWhiteList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/UserWhiteList.java.patch @@ -3,19 +3,19 @@ @@ -21,6 +_,11 @@ @Override - public boolean add(UserWhiteListEntry entry) { + public boolean add(final UserWhiteListEntry infos) { + // Paper start - Add whitelist events -+ if (!new io.papermc.paper.event.server.WhitelistStateUpdateEvent(com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(entry.getUser().toUncompletedGameProfile()), io.papermc.paper.event.server.WhitelistStateUpdateEvent.WhitelistStatus.ADDED).callEvent()) { ++ if (!new io.papermc.paper.event.server.WhitelistStateUpdateEvent(com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(infos.getUser().toUncompletedGameProfile()), io.papermc.paper.event.server.WhitelistStateUpdateEvent.WhitelistStatus.ADDED).callEvent()) { + return false; + } + // Paper end - Add whitelist events - if (super.add(entry)) { - if (entry.getUser() != null) { - this.notificationService.playerAddedToAllowlist(entry.getUser()); + if (super.add(infos)) { + if (infos.getUser() != null) { + this.notificationService.playerAddedToAllowlist(infos.getUser()); @@ -34,6 +_,11 @@ @Override - public boolean remove(NameAndId user) { + public boolean remove(final NameAndId user) { + // Paper start - Add whitelist events + if (!new io.papermc.paper.event.server.WhitelistStateUpdateEvent(com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(user.toUncompletedGameProfile()), io.papermc.paper.event.server.WhitelistStateUpdateEvent.WhitelistStatus.REMOVED).callEvent()) { + return false; diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch index ef6f7fc283cd..b190b42807ac 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch @@ -8,8 +8,8 @@ + public final java.net.SocketAddress socketAddress; + private final org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender remoteConsole = new org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender(this); -- public RconConsoleSource(MinecraftServer server) { -+ public RconConsoleSource(MinecraftServer server, java.net.SocketAddress socketAddress) { +- public RconConsoleSource(final MinecraftServer server) { ++ public RconConsoleSource(final MinecraftServer server, java.net.SocketAddress socketAddress) { + this.socketAddress = socketAddress; + // CraftBukkit end this.server = server; @@ -32,4 +32,4 @@ + // CraftBukkit end @Override - public void sendSystemMessage(Component message) { + public void sendSystemMessage(final Component message) { diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch index a2323578dd66..35ae01a2673f 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/server/rcon/thread/QueryThreadGs4.java +++ b/net/minecraft/server/rcon/thread/QueryThreadGs4.java @@ -105,13 +_,32 @@ - NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460); - networkDataOutputStream.write(0); - networkDataOutputStream.writeBytes(this.getIdentBytes(requestPacket.getSocketAddress())); -- networkDataOutputStream.writeString(this.serverName); + NetworkDataOutputStream dos = new NetworkDataOutputStream(1460); + dos.write(0); + dos.writeBytes(this.getIdentBytes(packet.getSocketAddress())); +- dos.writeString(this.serverName); + // Paper start + com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = + com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC; @@ -19,27 +19,27 @@ + .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) + .build(); + com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = -+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, requestPacket.getAddress(), queryResponse); ++ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); + queryEvent.callEvent(); + queryResponse = queryEvent.getResponse(); + -+ networkDataOutputStream.writeString(queryResponse.getMotd()); - networkDataOutputStream.writeString("SMP"); -- networkDataOutputStream.writeString(this.worldName); -- networkDataOutputStream.writeString(Integer.toString(this.serverInterface.getPlayerCount())); -- networkDataOutputStream.writeString(Integer.toString(this.maxPlayers)); -- networkDataOutputStream.writeShort((short)this.serverPort); -- networkDataOutputStream.writeString(this.hostIp); -+ networkDataOutputStream.writeString(queryResponse.getMap()); -+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getCurrentPlayers())); -+ networkDataOutputStream.writeString(Integer.toString(queryResponse.getMaxPlayers())); -+ networkDataOutputStream.writeShort((short) queryResponse.getPort()); -+ networkDataOutputStream.writeString(queryResponse.getHostname()); ++ dos.writeString(queryResponse.getMotd()); + dos.writeString("SMP"); +- dos.writeString(this.worldName); +- dos.writeString(Integer.toString(this.serverInterface.getPlayerCount())); +- dos.writeString(Integer.toString(this.maxPlayers)); +- dos.writeShort((short)this.serverPort); +- dos.writeString(this.hostIp); ++ dos.writeString(queryResponse.getMap()); ++ dos.writeString(Integer.toString(queryResponse.getCurrentPlayers())); ++ dos.writeString(Integer.toString(queryResponse.getMaxPlayers())); ++ dos.writeShort((short) queryResponse.getPort()); ++ dos.writeString(queryResponse.getHostname()); + // Paper end - this.sendTo(networkDataOutputStream.toByteArray(), requestPacket); + this.sendTo(dos.toByteArray(), packet); LOGGER.debug("Status [{}]", socketAddress); } -@@ -146,31 +_,75 @@ +@@ -146,31 +_,76 @@ this.rulesResponse.writeString("splitnum"); this.rulesResponse.write(128); this.rulesResponse.write(0); @@ -68,7 +68,7 @@ + com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = + com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL; + com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = -+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, requestPacket.getAddress(), queryResponse); ++ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); + queryEvent.callEvent(); + queryResponse = queryEvent.getResponse(); this.rulesResponse.writeString("hostname"); @@ -119,8 +119,9 @@ this.rulesResponse.write(1); this.rulesResponse.writeString("player_"); this.rulesResponse.write(0); -- String[] playerNames = this.serverInterface.getPlayerNames(); -+ String[] playerNames = queryResponse.getPlayers().toArray(String[]::new); +- String[] players = this.serverInterface.getPlayerNames(); ++ String[] players = queryResponse.getPlayers().toArray(String[]::new); ++ // Paper end - for (String string : playerNames) { - this.rulesResponse.writeString(string); + for (String player : players) { + this.rulesResponse.writeString(player); diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch index e84fb83f9d27..65e879ba64fc 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch @@ -10,11 +10,11 @@ + private final net.minecraft.server.rcon.RconConsoleSource rconConsoleSource; + // CraftBukkit end - RconClient(ServerInterface serverInterface, String rconPassword, Socket client) { - super("RCON Client " + client.getInetAddress()); + RconClient(final ServerInterface serverInterface, final String rconPassword, final Socket socket) { + super("RCON Client " + socket.getInetAddress()); - this.serverInterface = serverInterface; + this.serverInterface = (net.minecraft.server.dedicated.DedicatedServer) serverInterface; // CraftBukkit - this.client = client; + this.client = socket; try { @@ -37,6 +_,7 @@ @@ -26,11 +26,11 @@ @Override @@ -67,7 +_,7 @@ - String string1 = PktUtils.stringFromByteArray(this.buf, i1, i); + String command = PktUtils.stringFromByteArray(this.buf, offset, read); try { -- this.sendCmdResponse(i3, this.serverInterface.runCommand(string1)); -+ this.sendCmdResponse(i3, this.serverInterface.runCommand(this.rconConsoleSource, string1)); // CraftBukkit +- this.sendCmdResponse(requestid, this.serverInterface.runCommand(command)); ++ this.sendCmdResponse(requestid, this.serverInterface.runCommand(this.rconConsoleSource, command)); // CraftBukkit } catch (Exception var15) { - this.sendCmdResponse(i3, "Error executing: " + string1 + " (" + var15.getMessage() + ")"); + this.sendCmdResponse(requestid, "Error executing: " + command + " (" + var15.getMessage() + ")"); } diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconThread.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconThread.java.patch index bd7388039ad4..d2896e26aecb 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconThread.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconThread.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/server/rcon/thread/RconThread.java @@ -56,7 +_,7 @@ - public static @Nullable RconThread create(ServerInterface serverInterface) { - DedicatedServerProperties properties = serverInterface.getProperties(); + public static @Nullable RconThread create(final ServerInterface serverInterface) { + DedicatedServerProperties settings = serverInterface.getProperties(); - String serverIp = serverInterface.getServerIp(); -+ String serverIp = properties.rconIp; // Paper - Configurable rcon ip ++ String serverIp = settings.rconIp; // Paper - Configurable rcon ip if (serverIp.isEmpty()) { serverIp = "0.0.0.0"; } @@ -22,5 +22,5 @@ + } + // Paper end - don't wait for remote connections - private void closeSocket(ServerSocket socket) { + private void closeSocket(final ServerSocket socket) { LOGGER.debug("closeSocket: {}", socket); diff --git a/paper-server/patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch b/paper-server/patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch index 2a7a85913140..79fcad6dbccc 100644 --- a/paper-server/patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch +++ b/paper-server/patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch @@ -1,35 +1,35 @@ --- a/net/minecraft/stats/ServerRecipeBook.java +++ b/net/minecraft/stats/ServerRecipeBook.java @@ -64,17 +_,21 @@ - for (RecipeHolder recipeHolder : recipes) { - ResourceKey> resourceKey = recipeHolder.id(); - if (!this.known.contains(resourceKey) && !recipeHolder.value().isSpecial()) { + for (RecipeHolder recipe : recipes) { + ResourceKey> id = recipe.id(); + if (!this.known.contains(id) && !recipe.value().isSpecial()) { + // Paper start - PlayerRecipeDiscoverEvent event -+ final org.bukkit.event.player.PlayerRecipeDiscoverEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRecipeListUpdateEvent(player, recipeHolder); ++ final org.bukkit.event.player.PlayerRecipeDiscoverEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRecipeListUpdateEvent(player, recipe); + if (event.isCancelled()) continue; + // Paper end - PlayerRecipeDiscoverEvent event - this.add(resourceKey); - this.addHighlight(resourceKey); + this.add(id); + this.addHighlight(id); this.displayResolver .displaysForRecipe( -- resourceKey, entry -> list.add(new ClientboundRecipeBookAddPacket.Entry(entry, recipeHolder.value().showNotification(), true)) -+ resourceKey, entry -> list.add(new ClientboundRecipeBookAddPacket.Entry(entry, event.shouldShowNotification(), true)) // Paper - set notification from the event +- id, display -> recipesToAdd.add(new ClientboundRecipeBookAddPacket.Entry(display, recipe.value().showNotification(), true)) ++ id, display -> recipesToAdd.add(new ClientboundRecipeBookAddPacket.Entry(display, event.shouldShowNotification(), true)) // Paper - set notification from the event ); - CriteriaTriggers.RECIPE_UNLOCKED.trigger(player, recipeHolder); + CriteriaTriggers.RECIPE_UNLOCKED.trigger(player, recipe); } } -- if (!list.isEmpty()) { -+ if (!list.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent - player.connection.send(new ClientboundRecipeBookAddPacket(list, false)); +- if (!recipesToAdd.isEmpty()) { ++ if (!recipesToAdd.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent + player.connection.send(new ClientboundRecipeBookAddPacket(recipesToAdd, false)); } @@ -92,7 +_,7 @@ } } -- if (!list.isEmpty()) { -+ if (!list.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent - player.connection.send(new ClientboundRecipeBookRemovePacket(list)); +- if (!recipesToRemove.isEmpty()) { ++ if (!recipesToRemove.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent + player.connection.send(new ClientboundRecipeBookRemovePacket(recipesToRemove)); } diff --git a/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch b/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch index 5b95b1fbe6b1..a095b44e2e5a 100644 --- a/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch +++ b/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch @@ -25,9 +25,9 @@ @@ -91,6 +_,8 @@ @Override - public void setValue(Player player, Stat stat, int value) { + public void setValue(final Player player, final Stat stat, final int count) { + if (org.spigotmc.SpigotConfig.disableStatSaving) return; // Spigot + if (stat.getType() == Stats.CUSTOM && stat.getValue() instanceof final net.minecraft.resources.Identifier key && org.spigotmc.SpigotConfig.forcedStats.get(key) != null) return; // Paper - disable saving forced stats - super.setValue(player, stat, value); + super.setValue(player, stat, count); this.dirty.add(stat); } diff --git a/paper-server/patches/sources/net/minecraft/stats/StatsCounter.java.patch b/paper-server/patches/sources/net/minecraft/stats/StatsCounter.java.patch index a1a5baa22994..f9a20c28d116 100644 --- a/paper-server/patches/sources/net/minecraft/stats/StatsCounter.java.patch +++ b/paper-server/patches/sources/net/minecraft/stats/StatsCounter.java.patch @@ -2,14 +2,14 @@ +++ b/net/minecraft/stats/StatsCounter.java @@ -14,6 +_,12 @@ - public void increment(Player player, Stat stat, int amount) { - int i = (int)Math.min((long)this.getValue(stat) + amount, 2147483647L); + public void increment(final Player player, final Stat stat, final int count) { + int result = (int)Math.min((long)this.getValue(stat) + count, 2147483647L); + // CraftBukkit start - fire Statistic events -+ org.bukkit.event.Cancellable cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.handleStatisticsIncrease(player, stat, this.getValue(stat), i); ++ org.bukkit.event.Cancellable cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.handleStatisticsIncrease(player, stat, this.getValue(stat), result); + if (cancellable != null && cancellable.isCancelled()) { + return; + } + // CraftBukkit end - this.setValue(player, stat, i); + this.setValue(player, stat, result); } diff --git a/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch b/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch index 482a0e180c8e..09f37b6e02ff 100644 --- a/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch +++ b/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch @@ -1,68 +1,81 @@ --- a/net/minecraft/tags/TagLoader.java +++ b/net/minecraft/tags/TagLoader.java @@ -86,7 +_,10 @@ - return list.isEmpty() ? Either.right(List.copyOf(set)) : Either.left(list); + return missingElements.isEmpty() ? Either.right(List.copyOf(values)) : Either.left(missingElements); } -- public Map> build(Map> builders) { +- public Map> build(final Map> builders) { + // Paper start - fire tag registrar events + public Map> build(Map> builders, io.papermc.paper.tag.@Nullable TagEventConfig eventConfig) { + builders = io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.firePreFlattenEvent(builders, eventConfig); + // Paper end - final Map> map = new HashMap<>(); + final Map> newTags = new HashMap<>(); TagEntry.Lookup lookup = new TagEntry.Lookup() { - @Override -@@ -112,7 +_,7 @@ + { +@@ -116,7 +_,7 @@ ) - .ifRight(list -> map.put(path, (List)list)) + .ifRight(tag -> newTags.put(id, (List)tag)) ); -- return map; -+ return io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.firePostFlattenEvent(map, eventConfig); // Paper - fire tag registrar events +- return newTags; ++ return io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.firePostFlattenEvent(newTags, eventConfig); // Paper - fire tag registrar events } - public static void loadTagsFromNetwork(TagNetworkSerialization.NetworkPayload payload, WritableRegistry registry) { -@@ -120,16 +_,27 @@ + public static Map, List>> loadTagsFromNetwork(final TagNetworkSerialization.NetworkPayload tags, final Registry registry) { +@@ -124,18 +_,39 @@ } - public static List> loadTagsForExistingRegistries(ResourceManager resourceManager, RegistryAccess registryAccess) { + public static List> loadTagsForExistingRegistries(final ResourceManager manager, final RegistryAccess layer) { +- return layer.registries().map(entry -> loadPendingTags(manager, entry.value())).flatMap(Optional::stream).collect(Collectors.toUnmodifiableList()); + // Paper start - tag lifecycle - add cause -+ return loadTagsForExistingRegistries(resourceManager, registryAccess, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); ++ return loadTagsForExistingRegistries(manager, layer, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); + } + -+ public static List> loadTagsForExistingRegistries(ResourceManager resourceManager, RegistryAccess registryAccess, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) { ++ public static List> loadTagsForExistingRegistries( ++ final ResourceManager manager, final RegistryAccess layer, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause ++ ) { ++ return layer.registries().map(entry -> loadPendingTags(manager, entry.value(), cause)).flatMap(Optional::stream).collect(Collectors.toUnmodifiableList()); + // Paper end - tag lifecycle - add cause - return registryAccess.registries() -- .map(registryEntry -> loadPendingTags(resourceManager, registryEntry.value())) -+ .map(registryEntry -> loadPendingTags(resourceManager, registryEntry.value(), cause)) // Paper - tag lifecycle - add cause - .flatMap(Optional::stream) - .collect(Collectors.toUnmodifiableList()); } - public static void loadTagsForRegistry(ResourceManager resourceManager, WritableRegistry registry) { + public static void loadTagsForRegistry(final ResourceManager manager, final WritableRegistry registry) { +- loadTagsForRegistry(manager, registry.key(), TagLoader.ElementLookup.fromWritableRegistry(registry)); + // Paper start - tag lifecycle - add registrar event cause -+ loadTagsForRegistry(resourceManager, registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); ++ loadTagsForRegistry(manager, registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); + } -+ public static void loadTagsForRegistry(ResourceManager resourceManager, WritableRegistry registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) { ++ public static void loadTagsForRegistry(final ResourceManager manager, final WritableRegistry registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) { ++ loadTagsForRegistry(manager, registry.key(), TagLoader.ElementLookup.fromWritableRegistry(registry), registry, cause); + // Paper end - tag lifecycle - add registrar event cause - ResourceKey> resourceKey = registry.key(); - TagLoader> tagLoader = new TagLoader<>(TagLoader.ElementLookup.fromWritableRegistry(registry), Registries.tagsDirPath(resourceKey)); -- tagLoader.build(tagLoader.load(resourceManager)) -+ tagLoader.build(tagLoader.load(resourceManager), io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause)) // Paper - tag lifecycle - add registrar event cause - .forEach((identifier, list) -> registry.bindTag(TagKey.create(resourceKey, identifier), (List>)list)); } -@@ -137,12 +_,12 @@ - return tags.entrySet().stream().collect(Collectors.toUnmodifiableMap(entry -> TagKey.create(registryKey, entry.getKey()), Entry::getValue)); + public static Map, List>> loadTagsForRegistry( + final ResourceManager manager, final ResourceKey> registryKey, final TagLoader.ElementLookup> lookup + ) { ++ // Paper start - tag lifecycle - add registrar event cause ++ return loadTagsForRegistry(manager, registryKey, lookup, null, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); ++ } ++ ++ public static Map, List>> loadTagsForRegistry( ++ final ResourceManager manager, final ResourceKey> registryKey, final TagLoader.ElementLookup> lookup, final WritableRegistry registry, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause ++ ) { ++ // Paper end - tag lifecycle - add registrar event cause + TagLoader> loader = new TagLoader<>(lookup, Registries.tagsDirPath(registryKey)); +- return wrapTags(registryKey, loader.build(loader.load(manager))); ++ return wrapTags(registryKey, loader.build(loader.load(manager), io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause))); // Paper - tag lifecycle + } + + private static Map, List>> wrapTags( +@@ -144,12 +_,12 @@ + return tags.entrySet().stream().collect(Collectors.toUnmodifiableMap(e -> TagKey.create(registryKey, e.getKey()), Entry::getValue)); } -- private static Optional> loadPendingTags(ResourceManager resourceManager, Registry registry) { -+ private static Optional> loadPendingTags(ResourceManager resourceManager, Registry registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) { // Paper - add registrar event cause - ResourceKey> resourceKey = registry.key(); - TagLoader> tagLoader = new TagLoader<>( - (TagLoader.ElementLookup>)TagLoader.ElementLookup.fromFrozenRegistry(registry), Registries.tagsDirPath(resourceKey) +- private static Optional> loadPendingTags(final ResourceManager manager, final Registry registry) { ++ private static Optional> loadPendingTags(final ResourceManager manager, final Registry registry, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) { // Paper - add registrar event cause + ResourceKey> key = registry.key(); + TagLoader> loader = new TagLoader<>( + (TagLoader.ElementLookup>)TagLoader.ElementLookup.fromFrozenRegistry(registry), Registries.tagsDirPath(key) ); -- TagLoader.LoadResult loadResult = new TagLoader.LoadResult<>(resourceKey, wrapTags(registry.key(), tagLoader.build(tagLoader.load(resourceManager)))); -+ TagLoader.LoadResult loadResult = new TagLoader.LoadResult<>(resourceKey, wrapTags(registry.key(), tagLoader.build(tagLoader.load(resourceManager), io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause)))); // Paper - add registrar event cause - return loadResult.tags().isEmpty() ? Optional.empty() : Optional.of(registry.prepareTagReload(loadResult)); +- TagLoader.LoadResult tags = new TagLoader.LoadResult<>(key, wrapTags(registry.key(), loader.build(loader.load(manager)))); ++ TagLoader.LoadResult tags = new TagLoader.LoadResult<>(key, wrapTags(registry.key(), loader.build(loader.load(manager), io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause)))); // Paper - add registrar event cause + return tags.tags().isEmpty() ? Optional.empty() : Optional.of(registry.prepareTagReload(tags)); } diff --git a/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch b/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch index 8b6037975a17..fd298fb998c3 100644 --- a/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/util/PlaceholderLookupProvider.java +++ b/net/minecraft/util/PlaceholderLookupProvider.java -@@ -52,6 +_,13 @@ +@@ -57,6 +_,13 @@ ) ); } diff --git a/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch b/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch index 29822af20e8d..8de07f4f8ce7 100644 --- a/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch @@ -10,54 +10,54 @@ + private final int divideAdd; private final long divideAddUnsigned; // Paper - Perf: Optimize SimpleBitStorage private final int divideShift; - public SimpleBitStorage(int bits, int size, int[] data) { + public SimpleBitStorage(final int bits, final int size, final int[] values) { @@ -248,8 +_,8 @@ this.mask = (1L << bits) - 1L; this.valuesPerLong = (char)(64 / bits); - int i = 3 * (this.valuesPerLong - 1); -- this.divideMul = MAGIC[i + 0]; -- this.divideAdd = MAGIC[i + 1]; -+ this.divideMul = MAGIC[i + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper - Perf: Optimize SimpleBitStorage -+ this.divideAdd = MAGIC[i + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper - Perf: Optimize SimpleBitStorage - this.divideShift = MAGIC[i + 2]; - int i1 = (size + this.valuesPerLong - 1) / this.valuesPerLong; + int row = 3 * (this.valuesPerLong - 1); +- this.divideMul = MAGIC[row + 0]; +- this.divideAdd = MAGIC[row + 1]; ++ this.divideMul = MAGIC[row + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper - Perf: Optimize SimpleBitStorage ++ this.divideAdd = MAGIC[row + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper - Perf: Optimize SimpleBitStorage + this.divideShift = MAGIC[row + 2]; + int requiredLength = (size + this.valuesPerLong - 1) / this.valuesPerLong; if (data != null) { @@ -264,15 +_,11 @@ } - private int cellIndex(int index) { -- long l = Integer.toUnsignedLong(this.divideMul); -- long l1 = Integer.toUnsignedLong(this.divideAdd); -- return (int)(index * l + l1 >> 32 >> this.divideShift); -+ return (int)(index * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper - Perf: Optimize SimpleBitStorage + private int cellIndex(final int bitIndex) { +- long mul = Integer.toUnsignedLong(this.divideMul); +- long add = Integer.toUnsignedLong(this.divideAdd); +- return (int)(bitIndex * mul + add >> 32 >> this.divideShift); ++ return (int)(bitIndex * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper - Perf: Optimize SimpleBitStorage } @Override -- public int getAndSet(int index, int value) { +- public int getAndSet(final int index, final int value) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); - Validate.inclusiveBetween(0L, this.mask, (long)value); -+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; - int i1 = (index - i * this.valuesPerLong) * this.bits; ++ public final int getAndSet(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage + int cellIndex = this.cellIndex(index); + long cellValue = this.data[cellIndex]; + int bitIndex = (index - cellIndex * this.valuesPerLong) * this.bits; @@ -282,9 +_,7 @@ } @Override -- public void set(int index, int value) { +- public void set(final int index, final int value) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); - Validate.inclusiveBetween(0L, this.mask, (long)value); -+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; - int i1 = (index - i * this.valuesPerLong) * this.bits; ++ public final void set(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage + int cellIndex = this.cellIndex(index); + long cellValue = this.data[cellIndex]; + int bitIndex = (index - cellIndex * this.valuesPerLong) * this.bits; @@ -292,8 +_,7 @@ } @Override -- public int get(int index) { +- public int get(final int index) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage - int i = this.cellIndex(index); - long l = this.data[i]; - int i1 = (index - i * this.valuesPerLong) * this.bits; ++ public final int get(final int index) { // Paper - Perf: Optimize SimpleBitStorage + int cellIndex = this.cellIndex(index); + long cellValue = this.data[cellIndex]; + int bitIndex = (index - cellIndex * this.valuesPerLong) * this.bits; diff --git a/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch b/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch index f28bb2f44a3a..f4a2ad0d5ea7 100644 --- a/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch @@ -6,40 +6,40 @@ public class SpawnUtil { + public static Optional trySpawnMob( - EntityType entityType, - EntitySpawnReason spawnReason, + final EntityType entityType, + final EntitySpawnReason spawnReason, @@ -27,6 +_,24 @@ - SpawnUtil.Strategy strategy, - boolean checkCollision + final SpawnUtil.Strategy strategy, + final boolean checkCollisions ) { + // CraftBukkit start -+ return trySpawnMob(entityType, spawnReason, level, pos, attempts, range, yOffset, strategy, checkCollision, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT, null); // Paper - pre creature spawn event ++ return trySpawnMob(entityType, spawnReason, level, start, spawnAttempts, spawnRangeXZ, spawnRangeY, strategy, checkCollisions, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT, null); // Paper - pre creature spawn event + } + + public static Optional trySpawnMob( -+ EntityType entityType, -+ EntitySpawnReason spawnReason, -+ ServerLevel level, -+ BlockPos pos, -+ int attempts, -+ int range, -+ int yOffset, -+ SpawnUtil.Strategy strategy, -+ boolean checkCollision, -+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason, -+ @javax.annotation.Nullable Runnable onAbort // Paper - pre creature spawn event ++ final EntityType entityType, ++ final EntitySpawnReason spawnReason, ++ final ServerLevel level, ++ final BlockPos start, ++ final int spawnAttempts, ++ final int spawnRangeXZ, ++ final int spawnRangeY, ++ final SpawnUtil.Strategy strategy, ++ final boolean checkCollisions, ++ final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason, ++ final @org.jspecify.annotations.Nullable Runnable onAbort // Paper - pre creature spawn event + ) { + // CraftBukkit end - BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); + BlockPos.MutableBlockPos searchPos = start.mutable(); + RandomSource random = level.getRandom(); - for (int i = 0; i < attempts; i++) { -@@ -39,15 +_,32 @@ - !checkCollision - || level.noCollision(entityType.getSpawnAABB(mutableBlockPos.getX() + 0.5, mutableBlockPos.getY(), mutableBlockPos.getZ() + 0.5)) - )) { +@@ -37,15 +_,32 @@ + if (level.getWorldBorder().isWithinBounds(searchPos) + && moveToPossibleSpawnPosition(level, spawnRangeY, searchPos, strategy) + && (!checkCollisions || level.noCollision(entityType.getSpawnAABB(searchPos.getX() + 0.5, searchPos.getY(), searchPos.getZ() + 0.5)))) { + // Paper start - PreCreatureSpawnEvent + final com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(start, level), + org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entityType), + reason + ); @@ -53,7 +53,7 @@ + break; + } + // Paper end - PreCreatureSpawnEvent - T mob = (T)entityType.create(level, null, mutableBlockPos, spawnReason, false, false); + T mob = (T)entityType.create(level, null, searchPos, spawnReason, false, false); if (mob != null) { if (mob.checkSpawnRules(level, spawnReason) && mob.checkSpawnObstruction(level)) { - level.addFreshEntityWithPassengers(mob); diff --git a/paper-server/patches/sources/net/minecraft/util/StringUtil.java.patch b/paper-server/patches/sources/net/minecraft/util/StringUtil.java.patch index 99b603259661..3e115c789059 100644 --- a/paper-server/patches/sources/net/minecraft/util/StringUtil.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/StringUtil.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/util/StringUtil.java +++ b/net/minecraft/util/StringUtil.java @@ -85,6 +_,25 @@ - return stringBuilder.toString(); + return builder.toString(); } + // Paper start - Username validation @@ -23,6 +23,6 @@ + } + // Paper end - Username validation + - public static boolean isWhitespace(int character) { - return Character.isWhitespace(character) || Character.isSpaceChar(character); + public static boolean isWhitespace(final int codepoint) { + return Character.isWhitespace(codepoint) || Character.isSpaceChar(codepoint); } diff --git a/paper-server/patches/sources/net/minecraft/util/TickThrottler.java.patch b/paper-server/patches/sources/net/minecraft/util/TickThrottler.java.patch index b50d74a2be4f..32d86d8b6da4 100644 --- a/paper-server/patches/sources/net/minecraft/util/TickThrottler.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/TickThrottler.java.patch @@ -7,7 +7,7 @@ - private int count; + private final java.util.concurrent.atomic.AtomicInteger count = new java.util.concurrent.atomic.AtomicInteger(); // CraftBukkit - multithreaded field - public TickThrottler(int incrementStep, int threshold) { + public TickThrottler(final int incrementStep, final int threshold) { this.incrementStep = incrementStep; @@ -11,16 +_,31 @@ } diff --git a/paper-server/patches/sources/net/minecraft/util/Util.java.patch b/paper-server/patches/sources/net/minecraft/util/Util.java.patch index 02d529a2ced3..5e5da68f47bc 100644 --- a/paper-server/patches/sources/net/minecraft/util/Util.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/Util.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/util/Util.java +++ b/net/minecraft/util/Util.java -@@ -95,9 +_,25 @@ +@@ -96,9 +_,25 @@ private static final int DEFAULT_MAX_THREADS = 255; private static final int DEFAULT_SAFE_FILE_OPERATION_RETRIES = 10; private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads"; @@ -28,15 +28,15 @@ private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); public static final int LINEAR_LOOKUP_THRESHOLD = 8; private static final Set ALLOWED_UNTRUSTED_LINK_PROTOCOLS = Set.of("http", "https"); -@@ -116,6 +_,7 @@ +@@ -117,6 +_,7 @@ .findFirst() .orElseThrow(() -> new IllegalStateException("No jar file system provider found")); - private static Consumer thePauser = string -> {}; + private static Consumer thePauser = msg -> {}; + public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions public static Collector, ?, Map> toMap() { return Collectors.toMap(Entry::getKey, Entry::getValue); -@@ -138,7 +_,7 @@ +@@ -139,7 +_,7 @@ } public static long getNanos() { @@ -45,31 +45,31 @@ } public static long getEpochMillis() { -@@ -149,9 +_,10 @@ +@@ -150,9 +_,10 @@ return FILENAME_DATE_TIME_FORMATTER.format(ZonedDateTime.now()); } -- private static TracingExecutor makeExecutor(String name) { -+ private static TracingExecutor makeExecutor(String name, final int priorityModifier) { // Paper - Perf: add priority - int i = maxAllowedExecutorThreads(); -- ExecutorService directExecutorService; +- private static TracingExecutor makeExecutor(final String name) { ++ private static TracingExecutor makeExecutor(final String name, final int priorityModifier) { // Paper - Perf: add priority + int threads = maxAllowedExecutorThreads(); +- ExecutorService executor; + // Paper start - Perf: use simpler thread pool that allows 1 thread and reduce worldgen thread worker count for low core count CPUs -+ final ExecutorService directExecutorService; - if (i <= 0) { - directExecutorService = MoreExecutors.newDirectExecutorService(); ++ final ExecutorService executor; + if (threads <= 0) { + executor = MoreExecutors.newDirectExecutorService(); } else { -@@ -176,16 +_,30 @@ - super.onTermination(throwOnTermination); +@@ -177,16 +_,30 @@ + super.onTermination(exception); } }; -+ forkJoinWorkerThread.setPriority(Thread.NORM_PRIORITY + priorityModifier); // Paper - Deprioritize over main - forkJoinWorkerThread.setName(string); - return forkJoinWorkerThread; ++ thread.setPriority(Thread.NORM_PRIORITY + priorityModifier); // Paper - Deprioritize over main + thread.setName(threadName); + return thread; - }, Util::onThreadException, true); + }, Util::onThreadException, true, 0, Integer.MAX_VALUE, 1, null, 365, TimeUnit.DAYS); // Paper - do not expire threads } - return new TracingExecutor(directExecutorService); + return new TracingExecutor(executor); } public static int maxAllowedExecutorThreads() { @@ -91,7 +91,7 @@ } private static int getMaxThreads() { -@@ -235,6 +_,21 @@ +@@ -236,6 +_,21 @@ return thread; })); } @@ -111,5 +111,5 @@ + } + // Paper end - Separate dimension data IO pool - public static void throwAsRuntime(Throwable throwable) { + public static void throwAsRuntime(final Throwable throwable) { throw throwable instanceof RuntimeException ? (RuntimeException)throwable : new RuntimeException(throwable); diff --git a/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch b/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch index 93069aec3731..de6cbf1fea52 100644 --- a/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch @@ -4,28 +4,28 @@ } @Override -- public int getAndSet(int index, int value) { +- public int getAndSet(final int index, final int value) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); - Validate.inclusiveBetween(0L, 0L, (long)value); -+ public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage ++ public final int getAndSet(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage + //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage + //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage return 0; } @Override -- public void set(int index, int value) { +- public void set(final int index, final int value) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); - Validate.inclusiveBetween(0L, 0L, (long)value); -+ public final void set(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage ++ public final void set(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage + //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage + //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage } @Override -- public int get(int index) { +- public int get(final int index) { - Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -+ public final int get(int index) { // Paper - Perf: Optimize SimpleBitStorage ++ public final int get(final int index) { // Paper - Perf: Optimize SimpleBitStorage + //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage return 0; } diff --git a/paper-server/patches/sources/net/minecraft/util/datafix/DataFixers.java.patch b/paper-server/patches/sources/net/minecraft/util/datafix/DataFixers.java.patch index d89f25336169..7a93e5373491 100644 --- a/paper-server/patches/sources/net/minecraft/util/datafix/DataFixers.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/datafix/DataFixers.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/util/datafix/DataFixers.java +++ b/net/minecraft/util/datafix/DataFixers.java -@@ -534,6 +_,24 @@ - Schema schema44 = builder.addSchema(1456, SAME_NAMESPACED); - builder.addFixer(new EntityItemFrameDirectionFix(schema44, false)); - Schema schema45 = builder.addSchema(1458, V1458::new); +@@ -549,6 +_,24 @@ + Schema v1456 = fixerUpper.addSchema(1456, SAME_NAMESPACED); + fixerUpper.addFixer(new EntityItemFrameDirectionFix(v1456, false)); + Schema v1458 = fixerUpper.addSchema(1458, V1458::new); + // CraftBukkit start + // API allows setting player custom names, so we need to convert them. + // This does *not* handle upgrades in any other version, but generally those shouldn't need conversion. -+ builder.addFixer(new DataFix(schema45, false) { ++ fixerUpper.addFixer(new DataFix(v1458, false) { + @Override + protected TypeRewriteRule makeRule() { + return this.fixTypeEverywhereTyped("Player CustomName", this.getInputSchema().getType(References.PLAYER), typed -> { @@ -22,6 +22,6 @@ + } + }); + // CraftBukkit end - builder.addFixer(new EntityCustomNameToComponentFix(schema45)); - builder.addFixer(new ItemCustomNameToComponentFix(schema45)); - builder.addFixer(new BlockEntityCustomNameToComponentFix(schema45)); + fixerUpper.addFixer(new EntityCustomNameToComponentFix(v1458)); + fixerUpper.addFixer(new ItemCustomNameToComponentFix(v1458)); + fixerUpper.addFixer(new BlockEntityCustomNameToComponentFix(v1458)); diff --git a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java.patch b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java.patch index c40c8e02d28c..ffa5939b56ae 100644 --- a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java +++ b/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java @@ -29,7 +_,7 @@ - Dynamic dynamic = typed.get(DSL.remainderFinder()); - Typed typed1 = typed.getOrCreateTyped(opticFinder1); - Dynamic dynamic1 = typed1.get(DSL.remainderFinder()); -- dynamic1 = dynamic1.set("map", dynamic1.createInt(dynamic.get("Damage").asInt(0))); -+ if (dynamic1.getElement("map").result().isEmpty()) dynamic1 = dynamic1.set("map", dynamic1.createInt(dynamic.get("Damage").asInt(0))); // CraftBukkit - return typed.set(opticFinder1, typed1.set(DSL.remainderFinder(), dynamic1)); + Dynamic rest = input.get(DSL.remainderFinder()); + Typed tag = input.getOrCreateTyped(tagF); + Dynamic tagRest = tag.get(DSL.remainderFinder()); +- tagRest = tagRest.set("map", tagRest.createInt(rest.get("Damage").asInt(0))); ++ if (tagRest.getElement("map").result().isEmpty()) tagRest = tagRest.set("map", tagRest.createInt(rest.get("Damage").asInt(0))); // CraftBukkit + return input.set(tagF, tag.set(DSL.remainderFinder(), tagRest)); } else { - return typed; + return input; diff --git a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch index c20365405cf0..6573728534eb 100644 --- a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java +++ b/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java @@ -423,7 +_,7 @@ - if (DAMAGE_IDS.contains(optional.get().getSecond())) { - Typed typed2 = typed.getOrCreateTyped(opticFinder1); - Dynamic dynamic1 = typed2.get(DSL.remainderFinder()); -- dynamic1 = dynamic1.set("Damage", dynamic1.createInt(_int)); -+ if (_int != 0) dynamic1 = dynamic1.set("Damage", dynamic1.createInt(_int)); // CraftBukkit - typed1 = typed1.set(opticFinder1, typed2.set(DSL.remainderFinder(), dynamic1)); + if (DAMAGE_IDS.contains(id.get().getSecond())) { + Typed tag = input.getOrCreateTyped(tagF); + Dynamic tagRest = tag.get(DSL.remainderFinder()); +- tagRest = tagRest.set("Damage", tagRest.createInt(data)); ++ if (data != 0) tagRest = tagRest.set("Damage", tagRest.createInt(data)); // CraftBukkit + output = output.set(tagF, tag.set(DSL.remainderFinder(), tagRest)); } diff --git a/paper-server/patches/sources/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java.patch b/paper-server/patches/sources/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java.patch new file mode 100644 index 000000000000..338fe9d3c8ef --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java ++++ b/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java +@@ -145,7 +_,7 @@ + } + + Optional generatorIdentifier = Optional.ofNullable(Identifier.tryParse(chunkGeneratorType)); +- CompoundTag dataFixContext = ChunkMap.getChunkDataFixContextTag(dimensionKey, generatorIdentifier); ++ CompoundTag dataFixContext = ChunkMap.getChunkDataFixContextTag(ResourceKey.create(Registries.LEVEL_STEM, dimensionKey.identifier()), generatorIdentifier); // CraftBukkit + storeLegacyStructureDataToChunks(dimensionFixEntry.structures, chunkNbt, dataFixContext, upgradeProgress); + } + } diff --git a/paper-server/patches/sources/net/minecraft/util/random/WeightedList.java.patch b/paper-server/patches/sources/net/minecraft/util/random/WeightedList.java.patch index e67149c78ee4..7cc08b62e7e7 100644 --- a/paper-server/patches/sources/net/minecraft/util/random/WeightedList.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/random/WeightedList.java.patch @@ -11,17 +11,17 @@ private final List> items; private final WeightedList.@Nullable Selector selector; -- WeightedList(List> items) { -+ protected WeightedList(List> items) { // Paper - protected +- private WeightedList(final List> items) { ++ protected WeightedList(final List> items) { // Paper - protected this.items = List.copyOf(items); this.totalWeight = WeightedRandom.getTotalWeight(items, Weighted::weight); if (this.totalWeight == 0) { -@@ -128,7 +_,7 @@ +@@ -140,7 +_,7 @@ } public static class Builder { - private final ImmutableList.Builder> result = ImmutableList.builder(); + protected final ImmutableList.Builder> result = ImmutableList.builder(); - public WeightedList.Builder add(E element) { - return this.add(element, 1); + public WeightedList.Builder add(final E item) { + return this.add(item, 1); diff --git a/paper-server/patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch b/paper-server/patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch index 0e27c8dac9f8..9166a8d945c0 100644 --- a/paper-server/patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch @@ -1,15 +1,17 @@ --- a/net/minecraft/util/thread/BlockableEventLoop.java +++ b/net/minecraft/util/thread/BlockableEventLoop.java -@@ -33,6 +_,23 @@ +@@ -38,6 +_,45 @@ MetricsRegistry.INSTANCE.add(this); } + // Paper start -+ public final void executeAllRecentInternalTasks() { ++ public final boolean executeAllRecentInternalTasks() { + final int pending = this.pendingRunnables.size(); + + // note: due to possible recursive execution, we may execute more tasks than we want to + ++ int ran = 0; ++ + for (int i = 0; i < pending; ++i) { + final R run = this.pendingRunnables.poll(); + if (run == null) { @@ -17,15 +19,35 @@ + break; + } + this.doRunTask(run); ++ ++ran; ++ } ++ ++ return ran > 0; ++ } ++ ++ public boolean runTaskIf(final java.util.function.Predicate predicate) { ++ if (!this.isSameThread()) { ++ throw new IllegalStateException(); + } ++ ++ final R run = this.pendingRunnables.peek(); ++ if (run == null || (predicate != null && !predicate.test(run))) { ++ return false; ++ } ++ ++ this.pendingRunnables.remove(); ++ ++ this.doRunTask(run); ++ ++ return true; + } + // Paper end + - protected abstract boolean shouldRun(R runnable); + protected abstract boolean shouldRun(final R task); public boolean isSameThread() { -@@ -82,6 +_,14 @@ - task.run(); +@@ -87,6 +_,14 @@ + runnable.run(); } } + @@ -38,4 +60,4 @@ + // Paper end @Override - public void schedule(R task) { + public void schedule(final R r) { diff --git a/paper-server/patches/sources/net/minecraft/util/worldupdate/WorldUpgrader.java.patch b/paper-server/patches/sources/net/minecraft/util/worldupdate/WorldUpgrader.java.patch index fe6961f40b5f..f33982d80c30 100644 --- a/paper-server/patches/sources/net/minecraft/util/worldupdate/WorldUpgrader.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/worldupdate/WorldUpgrader.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/net/minecraft/util/worldupdate/WorldUpgrader.java -@@ -89,7 +_,7 @@ - boolean recreateRegionFiles +@@ -51,7 +_,7 @@ + final boolean recreateRegionFiles ) { this.dimensions = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); - this.levels = this.dimensions.registryKeySet().stream().map(Registries::levelStemToLevel).collect(Collectors.toUnmodifiableSet()); -+ this.levels = java.util.stream.Stream.of(levelStorage.dimensionType).map(Registries::levelStemToLevel).collect(Collectors.toUnmodifiableSet()); // CraftBukkit ++ this.levels = java.util.stream.Stream.of(levelSource.dimensionType).map(Registries::levelStemToLevel).collect(Collectors.toUnmodifiableSet()); // CraftBukkit this.eraseCache = eraseCache; this.dataFixer = dataFixer; - this.levelStorage = levelStorage; -@@ -367,7 +_,7 @@ - int dataVersion = NbtUtils.getDataVersion(compoundTag); - ChunkGenerator chunkGenerator = WorldUpgrader.this.dimensions.getValueOrThrow(Registries.levelToLevelStem(dimension)).generator(); - CompoundTag compoundTag1 = regionStorage.upgradeChunkTag( -- compoundTag, -1, ChunkMap.getChunkDataFixContextTag(dimension, chunkGenerator.getTypeNameForDataFixer()) -+ compoundTag, -1, ChunkMap.getChunkDataFixContextTag(Registries.levelToLevelStem(dimension), chunkGenerator.getTypeNameForDataFixer()), null // CraftBukkit - ); - ChunkPos chunkPos1 = new ChunkPos(compoundTag1.getIntOr("xPos", 0), compoundTag1.getIntOr("zPos", 0)); - if (!chunkPos1.equals(chunkPos)) { + this.levelStorage = levelSource; +@@ -68,7 +_,7 @@ + + public static CompoundTag getDataFixContextTag(final Registry dimensions, final ResourceKey dimension) { + ChunkGenerator generator = dimensions.getValueOrThrow(Registries.levelToLevelStem(dimension)).generator(); +- return ChunkMap.getChunkDataFixContextTag(dimension, generator.getTypeNameForDataFixer()); ++ return ChunkMap.getChunkDataFixContextTag(Registries.levelToLevelStem(dimension), generator.getTypeNameForDataFixer()); // CraftBukkit + } + + public static boolean verifyChunkPosAndEraseCache(final ChunkPos pos, final CompoundTag upgradedTag) { diff --git a/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch b/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch index 6d4cf0bfabe2..953650c178c1 100644 --- a/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch @@ -6,7 +6,7 @@ protected boolean createWorldFog; + public net.kyori.adventure.bossbar.BossBar adventure; // Paper - public BossEvent(UUID id, Component name, BossEvent.BossBarColor color, BossEvent.BossBarOverlay overlay) { + public BossEvent(final UUID id, final Component name, final BossEvent.BossBarColor color, final BossEvent.BossBarOverlay overlay) { this.id = id; @@ -29,61 +_,75 @@ } @@ -16,7 +16,7 @@ return this.name; } - public void setName(Component name) { + public void setName(final Component name) { + if (this.adventure != null) this.adventure.name(io.papermc.paper.adventure.PaperAdventure.asAdventure(name)); // Paper this.name = name; } @@ -26,7 +26,7 @@ return this.progress; } - public void setProgress(float progress) { + public void setProgress(final float progress) { + if (this.adventure != null) this.adventure.progress(progress); // Paper this.progress = progress; } @@ -36,7 +36,7 @@ return this.color; } - public void setColor(BossEvent.BossBarColor color) { + public void setColor(final BossEvent.BossBarColor color) { + if (this.adventure != null) this.adventure.color(io.papermc.paper.adventure.PaperAdventure.asAdventure(color)); // Paper this.color = color; } @@ -46,7 +46,7 @@ return this.overlay; } - public void setOverlay(BossEvent.BossBarOverlay overlay) { + public void setOverlay(final BossEvent.BossBarOverlay overlay) { + if (this.adventure != null) this.adventure.overlay(io.papermc.paper.adventure.PaperAdventure.asAdventure(overlay)); // Paper this.overlay = overlay; } @@ -56,9 +56,9 @@ return this.darkenScreen; } - public BossEvent setDarkenScreen(boolean darkenSky) { -+ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.DARKEN_SCREEN, darkenSky); // Paper - this.darkenScreen = darkenSky; + public BossEvent setDarkenScreen(final boolean darkenScreen) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.DARKEN_SCREEN, darkenScreen); // Paper + this.darkenScreen = darkenScreen; return this; } @@ -67,15 +67,15 @@ return this.playBossMusic; } - public BossEvent setPlayBossMusic(boolean playEndBossMusic) { -+ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.PLAY_BOSS_MUSIC, playEndBossMusic); // Paper - this.playBossMusic = playEndBossMusic; + public BossEvent setPlayBossMusic(final boolean playBossMusic) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.PLAY_BOSS_MUSIC, playBossMusic); // Paper + this.playBossMusic = playBossMusic; return this; } - public BossEvent setCreateWorldFog(boolean createFog) { -+ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.CREATE_WORLD_FOG, createFog); // Paper - this.createWorldFog = createFog; + public BossEvent setCreateWorldFog(final boolean createWorldFog) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.CREATE_WORLD_FOG, createWorldFog); // Paper + this.createWorldFog = createWorldFog; return this; } diff --git a/paper-server/patches/sources/net/minecraft/world/CompoundContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/CompoundContainer.java.patch index 8b3f531611dc..eb23c06dbef1 100644 --- a/paper-server/patches/sources/net/minecraft/world/CompoundContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/CompoundContainer.java.patch @@ -36,7 +36,7 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.inventory.InventoryHolder getOwner() { ++ public org.bukkit.inventory.@org.jspecify.annotations.Nullable InventoryHolder getOwner() { + return null; // This method won't be called since CraftInventoryDoubleChest doesn't defer to here + } + @@ -51,10 +51,10 @@ + } + // CraftBukkit end + - public CompoundContainer(Container container1, Container container2) { + public CompoundContainer(final Container container1, final Container container2) { this.container1 = container1; this.container2 = container2; -@@ -59,7 +_,7 @@ +@@ -57,7 +_,7 @@ @Override public int getMaxStackSize() { diff --git a/paper-server/patches/sources/net/minecraft/world/Container.java.patch b/paper-server/patches/sources/net/minecraft/world/Container.java.patch index b5e9379ac384..3cb5c688c52b 100644 --- a/paper-server/patches/sources/net/minecraft/world/Container.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/Container.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/Container.java +++ b/net/minecraft/world/Container.java -@@ -31,9 +_,7 @@ +@@ -32,9 +_,7 @@ - void setItem(int slot, ItemStack stack); + void setItem(int slot, ItemStack itemStack); - default int getMaxStackSize() { - return 99; - } + int getMaxStackSize(); // CraftBukkit - default int getMaxStackSize(ItemStack stack) { - return Math.min(this.getMaxStackSize(), stack.getMaxStackSize()); -@@ -142,4 +_,22 @@ + default int getMaxStackSize(final ItemStack itemStack) { + return Math.min(this.getMaxStackSize(), itemStack.getMaxStackSize()); +@@ -147,4 +_,22 @@ } } } @@ -25,11 +25,11 @@ + + java.util.List getViewers(); + -+ @javax.annotation.Nullable org.bukkit.inventory.InventoryHolder getOwner(); ++ org.bukkit.inventory.@Nullable InventoryHolder getOwner(); + + void setMaxStackSize(int size); + -+ @javax.annotation.Nullable org.bukkit.Location getLocation(); ++ org.bukkit.@Nullable Location getLocation(); + + int MAX_STACK = Item.ABSOLUTE_MAX_STACK_SIZE; + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch index 2b132d669a06..880febfa1f1c 100644 --- a/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch @@ -27,9 +27,9 @@ return true; } - public InteractionResult.Success heldItemTransformedTo(ItemStack stack) { -- return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, stack)); -+ return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, stack), this.paperSuccessContext); // Paper - track more context in interaction result + public InteractionResult.Success heldItemTransformedTo(final ItemStack itemStack) { +- return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, itemStack)); ++ return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, itemStack), this.paperSuccessContext); // Paper - track more context in interaction result } public InteractionResult.Success withoutItem() { diff --git a/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch b/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch index a031c69581ca..951cc1765580 100644 --- a/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/LockCode.java +++ b/net/minecraft/world/LockCode.java -@@ -22,8 +_,14 @@ +@@ -23,8 +_,14 @@ } } + @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - use new variant for event compatibility - public boolean canUnlock(Player player) { + public boolean canUnlock(final Player player) { - return player.isSpectator() || this.unlocksWith(player.getMainHandItem()); + // Paper start - allow overriding key item + return canUnlock(player, player.getMainHandItem()); @@ -15,4 +15,4 @@ + return player.isSpectator() || this.unlocksWith(item); // Paper - allow overriding key item } - public static LockCode fromTag(ValueInput input) { + public static LockCode fromTag(final ValueInput parent) { diff --git a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch index cf20d20fe90d..9cacb279dc3b 100644 --- a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch @@ -2,32 +2,32 @@ +++ b/net/minecraft/world/RandomizableContainer.java @@ -26,7 +_,7 @@ - void setLootTable(@Nullable ResourceKey lootTable); + void setLootTable(final @Nullable ResourceKey lootTable); -- default void setLootTable(ResourceKey lootTable, long seed) { -+ default void setLootTable(@Nullable ResourceKey lootTable, long seed) { // Paper - add nullable +- default void setLootTable(final ResourceKey lootTable, final long seed) { ++ default void setLootTable(final @Nullable ResourceKey lootTable, final long seed) { // Paper - add nullable this.setLootTable(lootTable); this.setLootTableSeed(seed); } -@@ -48,8 +_,9 @@ - default boolean tryLoadLootTable(ValueInput input) { - ResourceKey resourceKey = input.read("LootTable", LootTable.KEY_CODEC).orElse(null); - this.setLootTable(resourceKey); -+ if (this.lootableData() != null && resourceKey != null) this.lootableData().loadNbt(input); // Paper - LootTable API - this.setLootTableSeed(input.getLongOr("LootTableSeed", 0L)); -- return resourceKey != null; -+ return resourceKey != null && this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish +@@ -50,8 +_,9 @@ + default boolean tryLoadLootTable(final ValueInput base) { + ResourceKey lootTable = base.read("LootTable", LootTable.KEY_CODEC).orElse(null); + this.setLootTable(lootTable); ++ if (this.lootableData() != null && lootTable != null) this.lootableData().loadNbt(base); // Paper - LootTable API + this.setLootTableSeed(base.getLongOr("LootTableSeed", 0L)); +- return lootTable != null; ++ return lootTable != null && this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish } - default boolean trySaveLootTable(ValueOutput output) { -@@ -58,26 +_,42 @@ + default boolean trySaveLootTable(final ValueOutput base) { +@@ -60,26 +_,42 @@ return false; } else { - output.store("LootTable", LootTable.KEY_CODEC, lootTable); -+ if (this.lootableData() != null) this.lootableData().saveNbt(output); // Paper - LootTable API + base.store("LootTable", LootTable.KEY_CODEC, lootTable); ++ if (this.lootableData() != null) this.lootableData().saveNbt(base); // Paper - LootTable API long lootTableSeed = this.getLootTableSeed(); if (lootTableSeed != 0L) { - output.putLong("LootTableSeed", lootTableSeed); + base.putLong("LootTableSeed", lootTableSeed); } - return true; @@ -35,18 +35,18 @@ } } - default void unpackLootTable(@Nullable Player player) { + default void unpackLootTable(final @Nullable Player player) { + // Paper start - LootTable API + this.unpackLootTable(player, false); + } + default void unpackLootTable(@Nullable final Player player, final boolean forceClearLootTable) { + // Paper end - LootTable API Level level = this.getLevel(); - BlockPos blockPos = this.getBlockPos(); - ResourceKey lootTable = this.getLootTable(); -- if (lootTable != null && level != null && level.getServer() != null) { + BlockPos worldPosition = this.getBlockPos(); + ResourceKey lootTableKey = this.getLootTable(); +- if (lootTableKey != null && level != null && level.getServer() != null) { + // Paper start - LootTable API -+ lootReplenish: if (lootTable != null && level != null && level.getServer() != null) { ++ lootReplenish: if (lootTableKey != null && level != null && level.getServer() != null) { + if (this.lootableData() != null && !this.lootableData().shouldReplenish(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) { + if (forceClearLootTable) { + this.setLootTable(null); @@ -54,19 +54,19 @@ + break lootReplenish; + } + // Paper end - LootTable API - LootTable lootTable1 = level.getServer().reloadableRegistries().getLootTable(lootTable); + LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(lootTableKey); if (player instanceof ServerPlayer) { - CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, lootTable); + CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, lootTableKey); } + if (forceClearLootTable || this.lootableData() == null || this.lootableData().shouldClearLootTable(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) { // Paper - LootTable API this.setLootTable(null); + } // Paper - LootTable API - LootParams.Builder builder = new LootParams.Builder((ServerLevel)level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockPos)); + LootParams.Builder params = new LootParams.Builder((ServerLevel)level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(worldPosition)); if (player != null) { - builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player); -@@ -86,4 +_,16 @@ - lootTable1.fill(this, builder.create(LootContextParamSets.CHEST), this.getLootTableSeed()); + params.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player); +@@ -88,4 +_,16 @@ + lootTable.fill(this, params.create(LootContextParamSets.CHEST), this.getLootTableSeed()); } } + diff --git a/paper-server/patches/sources/net/minecraft/world/SimpleContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/SimpleContainer.java.patch index 5eeeade6049f..d16d9204ce28 100644 --- a/paper-server/patches/sources/net/minecraft/world/SimpleContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/SimpleContainer.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/SimpleContainer.java +++ b/net/minecraft/world/SimpleContainer.java -@@ -18,7 +_,90 @@ +@@ -15,7 +_,90 @@ + private final int size; public final NonNullList items; - private @Nullable List listeners; + // Paper start - add fields and methods + public List transaction = new java.util.ArrayList<>(); + private int maxStack = MAX_STACK; -+ protected org.bukkit.inventory.@Nullable InventoryHolder bukkitOwner; // Paper - annotation ++ protected org.bukkit.inventory.@org.jspecify.annotations.Nullable InventoryHolder bukkitOwner; // Paper - annotation + + @Override + public List getContents() { @@ -40,7 +40,7 @@ + } + + @Override -+ public org.bukkit.inventory.@Nullable InventoryHolder getOwner() { ++ public org.bukkit.inventory.@org.jspecify.annotations.Nullable InventoryHolder getOwner() { + // Paper start - Add missing InventoryHolders + if (this.bukkitOwner == null && this.bukkitOwnerCreator != null) { + this.bukkitOwner = this.bukkitOwnerCreator.get(); @@ -50,7 +50,7 @@ + } + + @Override -+ public org.bukkit.@Nullable Location getLocation() { ++ public org.bukkit.@org.jspecify.annotations.Nullable Location getLocation() { + // Paper start - Fix inventories returning null Locations + // When the block inventory does not have a tile state that implements getLocation, e. g. composters + if (this.bukkitOwner instanceof org.bukkit.inventory.BlockInventoryHolder blockInventoryHolder) { @@ -72,12 +72,12 @@ + } + // Paper end + - public SimpleContainer(int size) { + public SimpleContainer(final int size) { + this(size, null); + } + + // Paper start - Add missing InventoryHolders -+ private java.util.function.@Nullable Supplier bukkitOwnerCreator; ++ private java.util.function.@org.jspecify.annotations.Nullable Supplier bukkitOwnerCreator; + + public SimpleContainer(java.util.function.Supplier bukkitOwnerCreator, int size) { + this(size); @@ -85,7 +85,7 @@ + } + // Paper end - Add missing InventoryHolders + -+ public SimpleContainer(int size, org.bukkit.inventory.@Nullable InventoryHolder owner) { ++ public SimpleContainer(final int size, final org.bukkit.inventory.@org.jspecify.annotations.Nullable InventoryHolder owner) { + this.bukkitOwner = owner; + // Paper end this.size = size; diff --git a/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch b/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch new file mode 100644 index 000000000000..7722ffc60843 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch @@ -0,0 +1,53 @@ +--- a/net/minecraft/world/clock/ServerClockManager.java ++++ b/net/minecraft/world/clock/ServerClockManager.java +@@ -97,7 +_,16 @@ + return set.booleanValue(); + } + +- public void addTicks(final Holder clock, final int ticks) { ++ // Paper start - time skip event ++ public java.util.OptionalLong getTotalTicksToTimeMarker(final Holder clock, final ResourceKey timeMarkerId) { ++ final ServerClockManager.ClockInstance instance = this.getInstance(clock); ++ final ClockTimeMarker timeMarker = instance.timeMarkers.get(timeMarkerId); ++ ++ return timeMarker != null ? java.util.OptionalLong.of(timeMarker.resolveTimeToMoveTo(instance.totalTicks)) : java.util.OptionalLong.empty(); ++ } ++ // Paper end - time skip event ++ ++ public void addTicks(final Holder clock, final long ticks) { // Paper + this.modifyClock(clock, instance -> instance.totalTicks = Math.max(instance.totalTicks + ticks, 0L)); + } + +@@ -113,7 +_,7 @@ + ServerClockManager.ClockInstance instance = this.getInstance(clock); + action.accept(instance); + Map, ClockNetworkState> updates = Map.of(clock, instance.packNetworkState(this.server)); +- this.server.getPlayerList().broadcastAll(new ClientboundSetTimePacket(this.getGameTime(), updates)); ++ this.server.getPlayerList().broadcastAll(new ClientboundSetTimePacket(this.getGameTime(), updates)); // TODO 26.1 per-player time + this.setDirty(); + + for (ServerLevel level : this.server.getAllLevels()) { +@@ -126,7 +_,23 @@ + return this.getInstance(definition).totalTicks; + } + ++ // Paper start ++ // TODO - snapshot: just make the inner class, fields and getter public ++ public boolean isPaused(final Holder definition) { ++ return this.getInstance(definition).paused; ++ } ++ ++ public float partialTick(final Holder definition) { ++ return this.getInstance(definition).partialTick; ++ } ++ ++ public float rate(final Holder definition) { ++ return this.getInstance(definition).rate; ++ } ++ // Paper end ++ + public ClientboundSetTimePacket createFullSyncPacket() { ++ // TODO - snapshot: 26.1 per-player time + return new ClientboundSetTimePacket(this.getGameTime(), Util.mapValues(this.clocks, clock -> clock.packNetworkState(this.server))); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch b/paper-server/patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch index 9f7b4e9b5d5c..b4c24f057a19 100644 --- a/paper-server/patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch @@ -6,29 +6,29 @@ public boolean takingDamage; + public final io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper paperCombatTracker; // Paper - Combat tracker API - public CombatTracker(LivingEntity mob) { + public CombatTracker(final LivingEntity mob) { this.mob = mob; + this.paperCombatTracker = new io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper(this); // Paper - Combat tracker API } - public void recordDamage(DamageSource source, float damage) { + public void recordDamage(final DamageSource source, final float damage) { this.recheckStatus(); - FallLocation currentFallLocation = FallLocation.getCurrentFallLocation(this.mob); - CombatEntry combatEntry = new CombatEntry(source, damage, currentFallLocation, (float)this.mob.fallDistance); + FallLocation fallLocation = FallLocation.getCurrentFallLocation(this.mob); + CombatEntry entry = new CombatEntry(source, damage, fallLocation, (float)this.mob.fallDistance); + // Paper start - Combat tracker API -+ recordDamageAndCheckCombatState(combatEntry); ++ recordDamageAndCheckCombatState(entry); + } + -+ public void recordDamageAndCheckCombatState(final CombatEntry combatEntry) { -+ final DamageSource source = combatEntry.source(); ++ public void recordDamageAndCheckCombatState(final CombatEntry entry) { ++ final DamageSource source = entry.source(); + // Paper end - Combat tracker API - this.entries.add(combatEntry); + this.entries.add(entry); this.lastDamageTime = this.mob.tickCount; this.takingDamage = true; -@@ -145,6 +_,13 @@ +@@ -147,6 +_,13 @@ public void recheckStatus() { - int i = this.inCombat ? 300 : 100; - if (this.takingDamage && (!this.mob.isAlive() || this.mob.tickCount - this.lastDamageTime > i)) { + int reset = this.inCombat ? 300 : 100; + if (this.takingDamage && (!this.mob.isAlive() || this.mob.tickCount - this.lastDamageTime > reset)) { + // Paper start - Combat tracker API + resetCombatState(); + } @@ -36,6 +36,6 @@ + + public void resetCombatState() {{ + // Paper end - Combat tracker API - boolean flag = this.inCombat; + boolean wasInCombat = this.inCombat; this.takingDamage = false; this.inCombat = false; diff --git a/paper-server/patches/sources/net/minecraft/world/effect/HealOrHarmMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/HealOrHarmMobEffect.java.patch index 274a719765de..0a7679430e14 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/HealOrHarmMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/HealOrHarmMobEffect.java.patch @@ -2,22 +2,22 @@ +++ b/net/minecraft/world/effect/HealOrHarmMobEffect.java @@ -16,7 +_,7 @@ @Override - public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { - if (this.isHarm == entity.isInvertedHealAndHarm()) { -- entity.heal(Math.max(4 << amplifier, 0)); -+ entity.heal(Math.max(4 << amplifier, 0), org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC); // CraftBukkit + public boolean applyEffectTick(final ServerLevel level, final LivingEntity mob, final int amplification) { + if (this.isHarm == mob.isInvertedHealAndHarm()) { +- mob.heal(Math.max(4 << amplification, 0)); ++ mob.heal(Math.max(4 << amplification, 0), org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC); // CraftBukkit } else { - entity.hurtServer(level, entity.damageSources().magic(), 6 << amplifier); + mob.hurtServer(level, mob.damageSources().magic(), 6 << amplification); } -@@ -28,9 +_,10 @@ - public void applyInstantenousEffect( - ServerLevel level, @Nullable Entity source, @Nullable Entity indirectSource, LivingEntity entity, int amplifier, double health +@@ -33,9 +_,10 @@ + final int amplification, + final double scale ) { -+ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplifier).callEvent()) { return; } // Paper - Add EntityEffectTickEvent - if (this.isHarm == entity.isInvertedHealAndHarm()) { - int i = (int)(health * (4 << amplifier) + 0.5); -- entity.heal(i); -+ entity.heal(i, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC); // CraftBukkit ++ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(mob.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplification).callEvent()) { return; } // Paper - Add EntityEffectTickEvent + if (this.isHarm == mob.isInvertedHealAndHarm()) { + int amount = (int)(scale * (4 << amplification) + 0.5); +- mob.heal(amount); ++ mob.heal(amount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC); // CraftBukkit } else { - int i = (int)(health * (6 << amplifier) + 0.5); + int amount = (int)(scale * (6 << amplification) + 0.5); if (source == null) { diff --git a/paper-server/patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch index 0328a5b344a3..c6284d81dd1b 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/effect/HungerMobEffect.java @@ -12,7 +_,7 @@ @Override - public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { - if (entity instanceof Player player) { -- player.causeFoodExhaustion(0.005F * (amplifier + 1)); -+ player.causeFoodExhaustion(0.005F * (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent + public boolean applyEffectTick(final ServerLevel serverLevel, final LivingEntity mob, final int amplification) { + if (mob instanceof Player player) { +- player.causeFoodExhaustion(0.005F * (amplification + 1)); ++ player.causeFoodExhaustion(0.005F * (amplification + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent } return true; diff --git a/paper-server/patches/sources/net/minecraft/world/effect/InfestedMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/InfestedMobEffect.java.patch index b7ef4b139bfa..da1d18f2e2e3 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/InfestedMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/InfestedMobEffect.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/effect/InfestedMobEffect.java +++ b/net/minecraft/world/effect/InfestedMobEffect.java @@ -44,7 +_,11 @@ - Vector3f vector3f = entity.getLookAngle().toVector3f().mul(0.3F).mul(1.0F, 1.5F, 1.0F).rotateY(f1); + Vector3f viewDirection = mob.getLookAngle().toVector3f().mul(0.3F).mul(1.0F, 1.5F, 1.0F).rotateY(randomAngle); silverfish.snapTo(x, y, z, level.getRandom().nextFloat() * 360.0F, 0.0F); - silverfish.setDeltaMovement(new Vec3(vector3f)); + silverfish.setDeltaMovement(new Vec3(viewDirection)); - level.addFreshEntity(silverfish); + // CraftBukkit start + if (!level.addFreshEntity(silverfish, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.POTION_EFFECT)) { diff --git a/paper-server/patches/sources/net/minecraft/world/effect/MobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/MobEffect.java.patch index 1d9da101bd4a..4d28b906bda9 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/MobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/MobEffect.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/effect/MobEffect.java +++ b/net/minecraft/world/effect/MobEffect.java -@@ -85,6 +_,7 @@ - public void applyInstantenousEffect( - ServerLevel level, @Nullable Entity source, @Nullable Entity indirectSource, LivingEntity entity, int amplifier, double health +@@ -90,6 +_,7 @@ + final int amplification, + final double scale ) { -+ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplifier).callEvent()) { return; } // Paper - Add EntityEffectTickEvent - this.applyEffectTick(level, entity, amplifier); ++ if (!new io.papermc.paper.event.entity.EntityEffectTickEvent(mob.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(this), amplification).callEvent()) { return; } // Paper - Add EntityEffectTickEvent + this.applyEffectTick(level, mob, amplification); } diff --git a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch index e7e66807e993..a037d0743c48 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch @@ -1,15 +1,14 @@ --- a/net/minecraft/world/effect/MobEffectInstance.java +++ b/net/minecraft/world/effect/MobEffectInstance.java -@@ -218,7 +_,7 @@ - return false; +@@ -227,6 +_,7 @@ } else { - int i = this.isInfiniteDuration() ? entity.tickCount : this.duration; -- if (this.effect.value().shouldApplyEffectTickThisTick(i, this.amplifier) && !this.effect.value().applyEffectTick(level, entity, this.amplifier)) { -+ if (this.effect.value().shouldApplyEffectTickThisTick(i, this.amplifier) && new io.papermc.paper.event.entity.EntityEffectTickEvent(entity.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(this.effect), this.amplifier).callEvent() && !this.effect.value().applyEffectTick(level, entity, this.amplifier)) { // Paper - Add EntityEffectTickEvent + int tickCount = this.isInfiniteDuration() ? target.tickCount : this.duration; + if (this.effect.value().shouldApplyEffectTickThisTick(tickCount, this.amplifier) ++ && new io.papermc.paper.event.entity.EntityEffectTickEvent(target.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(this.effect), this.amplifier).callEvent() // Paper - Add EntityEffectTickEvent + && !this.effect.value().applyEffectTick(serverLevel, target, this.amplifier)) { return false; } else { - this.tickDownDuration(); -@@ -253,13 +_,16 @@ +@@ -262,13 +_,16 @@ } private boolean downgradeToHiddenEffect() { @@ -30,22 +29,22 @@ + // Paper end - Fix MC-259832 } - public void onEffectStarted(LivingEntity entity) { -@@ -414,7 +_,7 @@ - .apply(instance, MobEffectInstance.Details::create) + public void onEffectStarted(final LivingEntity mob) { +@@ -425,7 +_,7 @@ + .apply(i, MobEffectInstance.Details::create) ) ); - public static final StreamCodec STREAM_CODEC = StreamCodec.recursive( + public static final StreamCodec STREAM_CODEC = StreamCodec.recursive( // Paper - Track codec depth - codec -> StreamCodec.composite( + subCodec -> StreamCodec.composite( ByteBufCodecs.VAR_INT, MobEffectInstance.Details::amplifier, -@@ -426,7 +_,7 @@ +@@ -437,7 +_,7 @@ MobEffectInstance.Details::showParticles, ByteBufCodecs.BOOL, MobEffectInstance.Details::showIcon, -- codec.apply(ByteBufCodecs::optional), -+ codec.apply(ByteBufCodecs::increaseDepth).apply(ByteBufCodecs::optional), // Paper - Track codec depth +- subCodec.apply(ByteBufCodecs::optional), ++ subCodec.apply(ByteBufCodecs::increaseDepth).apply(ByteBufCodecs::optional), // Paper - Track codec depth MobEffectInstance.Details::hiddenEffect, MobEffectInstance.Details::new ) diff --git a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectUtil.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectUtil.java.patch index 54b2f1ba668e..40a12687af8b 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectUtil.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectUtil.java.patch @@ -1,48 +1,62 @@ --- a/net/minecraft/world/effect/MobEffectUtil.java +++ b/net/minecraft/world/effect/MobEffectUtil.java -@@ -55,18 +_,38 @@ - public static List addEffectToPlayersAround( - ServerLevel level, @Nullable Entity source, Vec3 pos, double radius, MobEffectInstance effect, int duration +@@ -56,18 +_,56 @@ + final MobEffectInstance effectInstance, + final int displayEffectLimit ) { + // CraftBukkit start -+ return MobEffectUtil.addEffectToPlayersAround(level, source, pos, radius, effect, duration, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); ++ return MobEffectUtil.addEffectToPlayersAround(level, source, position, radius, effectInstance, displayEffectLimit, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + } + -+ public static List addEffectToPlayersAround(ServerLevel level, @Nullable Entity source, Vec3 pos, double radius, MobEffectInstance effect, int duration, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { ++ public static List addEffectToPlayersAround( ++ final ServerLevel level, ++ final @Nullable Entity source, ++ final Vec3 position, ++ final double radius, ++ final MobEffectInstance effectInstance, ++ final int displayEffectLimit, ++ final org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause ++ ) { + // Paper start - Add ElderGuardianAppearanceEvent -+ return addEffectToPlayersAround(level, source, pos, radius, effect, duration, cause, null); ++ return addEffectToPlayersAround(level, source, position, radius, effectInstance, displayEffectLimit, cause, null); + } + -+ public static List addEffectToPlayersAround(ServerLevel level, @Nullable Entity source, Vec3 pos, double radius, MobEffectInstance effect, int duration, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause, java.util.function.@Nullable Predicate playerPredicate) { ++ public static List addEffectToPlayersAround( ++ final ServerLevel level, ++ final @Nullable Entity source, ++ final Vec3 position, ++ final double radius, ++ final MobEffectInstance effectInstance, ++ final int displayEffectLimit, ++ final org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause, ++ final java.util.function.@Nullable Predicate playerPredicate ++ ) { + // Paper end - Add ElderGuardianAppearanceEvent + // CraftBukkit end - Holder effect1 = effect.getEffect(); + Holder effect = effectInstance.getEffect(); List players = level.getPlayers( -- serverPlayer -> serverPlayer.gameMode.isSurvival() +- input -> input.gameMode.isSurvival() + // Paper start - Add ElderGuardianAppearanceEvent -+ serverPlayer -> { -+ final boolean condition = serverPlayer.gameMode.isSurvival() - && (source == null || !source.isAlliedTo(serverPlayer)) - && pos.closerThan(serverPlayer.position(), radius) ++ input -> { ++ final boolean condition = input.gameMode.isSurvival() + && (source == null || !source.isAlliedTo(input)) + && position.closerThan(input.position(), radius) && ( -- !serverPlayer.hasEffect(effect1) -- || serverPlayer.getEffect(effect1).getAmplifier() < effect.getAmplifier() -- || serverPlayer.getEffect(effect1).endsWithin(duration - 1) + !input.hasEffect(effect) + || input.getEffect(effect).getAmplifier() < effectInstance.getAmplifier() + || input.getEffect(effect).endsWithin(displayEffectLimit - 1) - ) -- ); -- players.forEach(serverPlayer -> serverPlayer.addEffect(new MobEffectInstance(effect), source)); -+ !serverPlayer.hasEffect(effect1) -+ || serverPlayer.getEffect(effect1).getAmplifier() < effect.getAmplifier() -+ || serverPlayer.getEffect(effect1).endsWithin(duration - 1) -+ ); -+ if (condition) { -+ return playerPredicate == null || playerPredicate.test(serverPlayer); // Only test the player AFTER it is true -+ } else { -+ return false; ++ ); ++ if (condition) { ++ return playerPredicate == null || playerPredicate.test(input); // Only test the player AFTER it is true ++ } else { ++ return false; ++ } + } -+ }); + ); +- players.forEach(player -> player.addEffect(new MobEffectInstance(effectInstance), source)); + // Paper end - Add ElderGuardianAppearanceEvent -+ players.forEach(serverPlayer -> serverPlayer.addEffect(new MobEffectInstance(effect), source, cause)); // CraftBukkit ++ players.forEach(player -> player.addEffect(new MobEffectInstance(effectInstance), source, cause)); // CraftBukkit return players; } } diff --git a/paper-server/patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch index 756bcf1d8893..23e24bdf6df0 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/effect/PoisonMobEffect.java @@ -13,7 +_,7 @@ @Override - public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { - if (entity.getHealth() > 1.0F) { -- entity.hurtServer(level, entity.damageSources().magic(), 1.0F); -+ entity.hurtServer(level, entity.damageSources().magic().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.POISON), 1.0F); // CraftBukkit + public boolean applyEffectTick(final ServerLevel level, final LivingEntity mob, final int amplification) { + if (mob.getHealth() > 1.0F) { +- mob.hurtServer(level, mob.damageSources().magic(), 1.0F); ++ mob.hurtServer(level, mob.damageSources().magic().knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.POISON), 1.0F); // CraftBukkit } return true; diff --git a/paper-server/patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch index c7b4805bbb37..a85c115a311b 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/effect/RegenerationMobEffect.java @@ -11,7 +_,7 @@ @Override - public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { - if (entity.getHealth() < entity.getMaxHealth()) { -- entity.heal(1.0F); -+ entity.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit + public boolean applyEffectTick(final ServerLevel level, final LivingEntity mob, final int amplification) { + if (mob.getHealth() < mob.getMaxHealth()) { +- mob.heal(1.0F); ++ mob.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit } return true; diff --git a/paper-server/patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch index d9dff0017600..040d7f476b31 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch @@ -2,12 +2,12 @@ +++ b/net/minecraft/world/effect/SaturationMobEffect.java @@ -12,7 +_,15 @@ @Override - public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { - if (entity instanceof Player player) { -- player.getFoodData().eat(amplifier + 1, 1.0F); + public boolean applyEffectTick(final ServerLevel level, final LivingEntity mob, final int amplification) { + if (mob instanceof Player player) { +- player.getFoodData().eat(amplification + 1, 1.0F); + // CraftBukkit start + int oldFoodLevel = player.getFoodData().foodLevel; -+ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, amplifier + 1 + oldFoodLevel); ++ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, amplification + 1 + oldFoodLevel); + if (!event.isCancelled()) { + player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F); + } diff --git a/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch index 3e0ba111f71b..711b4be6fc30 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch @@ -2,22 +2,22 @@ +++ b/net/minecraft/world/effect/WeavingMobEffect.java @@ -27,11 +_,11 @@ @Override - public void onMobRemoved(ServerLevel level, LivingEntity entity, int amplifier, Entity.RemovalReason reason) { - if (reason == Entity.RemovalReason.KILLED && (entity instanceof Player || level.getGameRules().get(GameRules.MOB_GRIEFING))) { -- this.spawnCobwebsRandomlyAround(level, entity.getRandom(), entity.blockPosition()); -+ this.spawnCobwebsRandomlyAround(level, entity.getRandom(), entity.blockPosition(), entity); // Paper - Fire EntityChangeBlockEvent in more places + public void onMobRemoved(final ServerLevel level, final LivingEntity mob, final int amplifier, final Entity.RemovalReason reason) { + if (reason == Entity.RemovalReason.KILLED && (mob instanceof Player || level.getGameRules().get(GameRules.MOB_GRIEFING))) { +- this.spawnCobwebsRandomlyAround(level, mob.getRandom(), mob.blockPosition()); ++ this.spawnCobwebsRandomlyAround(level, mob.getRandom(), mob.blockPosition(), mob); // Paper - Fire EntityChangeBlockEvent in more places } } -- private void spawnCobwebsRandomlyAround(ServerLevel level, RandomSource random, BlockPos pos) { -+ private void spawnCobwebsRandomlyAround(ServerLevel level, RandomSource random, BlockPos pos, LivingEntity entity) { // Paper - Fire EntityChangeBlockEvent in more places - Set set = Sets.newHashSet(); - int i = this.maxCobwebs.applyAsInt(random); +- private void spawnCobwebsRandomlyAround(final ServerLevel level, final RandomSource random, final BlockPos pos) { ++ private void spawnCobwebsRandomlyAround(final ServerLevel level, final RandomSource random, final BlockPos pos, LivingEntity entity) { // Paper - Fire EntityChangeBlockEvent in more places + Set positionsToTransform = Sets.newHashSet(); + int cobwebCount = this.maxCobwebs.applyAsInt(random); @@ -48,6 +_,7 @@ } - for (BlockPos blockPosx : set) { + for (BlockPos blockPosx : positionsToTransform) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPosx, Blocks.COBWEB.defaultBlockState())) continue; // Paper - Fire EntityChangeBlockEvent in more places level.setBlock(blockPosx, Blocks.COBWEB.defaultBlockState(), Block.UPDATE_ALL); level.levelEvent(LevelEvent.ANIMATION_SPAWN_COBWEB, blockPosx, 0); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/AgeableMob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/AgeableMob.java.patch deleted file mode 100644 index 6c83aa84c19b..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/entity/AgeableMob.java.patch +++ /dev/null @@ -1,43 +0,0 @@ ---- a/net/minecraft/world/entity/AgeableMob.java -+++ b/net/minecraft/world/entity/AgeableMob.java -@@ -23,6 +_,7 @@ - protected int age = 0; - protected int forcedAge = 0; - protected int forcedAgeTimer; -+ public boolean ageLocked; // CraftBukkit - - protected AgeableMob(EntityType type, Level level) { - super(type, level); -@@ -68,6 +_,7 @@ - } - - public void ageUp(int amount, boolean forced) { -+ if (this.ageLocked) return; // Paper - Honor ageLock - int age = this.getAge(); - int previousAge = age; - age += amount * 20; -@@ -107,6 +_,7 @@ - super.addAdditionalSaveData(output); - output.putInt("Age", this.getAge()); - output.putInt("ForcedAge", this.forcedAge); -+ output.putBoolean("AgeLocked", this.ageLocked); // CraftBukkit - } - - @Override -@@ -114,6 +_,7 @@ - super.readAdditionalSaveData(input); - this.setAge(input.getIntOr("Age", 0)); - this.forcedAge = input.getIntOr("ForcedAge", 0); -+ this.ageLocked = input.getBooleanOr("AgeLocked", false); // CraftBukkit - } - - @Override -@@ -136,7 +_,7 @@ - - this.forcedAgeTimer--; - } -- } else if (this.isAlive()) { -+ } else if (!this.ageLocked && this.isAlive()) { // CraftBukkit - int age = this.getAge(); - if (age < 0) { - this.setAge(++age); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/AreaEffectCloud.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/AreaEffectCloud.java.patch index 0acae96c2e8e..6ebd8b3cadb0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/AreaEffectCloud.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/AreaEffectCloud.java.patch @@ -2,13 +2,13 @@ +++ b/net/minecraft/world/entity/AreaEffectCloud.java @@ -189,7 +_,7 @@ - private void serverTick(ServerLevel level) { + private void serverTick(final ServerLevel serverLevel) { if (this.duration != -1 && this.tickCount - this.waitTime >= this.duration) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else { boolean isWaiting = this.isWaiting(); - boolean flag = this.tickCount < this.waitTime; + boolean shouldWait = this.tickCount < this.waitTime; @@ -202,7 +_,7 @@ if (this.radiusPerTick != 0.0F) { radius += this.radiusPerTick; @@ -18,38 +18,37 @@ return; } -@@ -218,6 +_,7 @@ - this.potionContents.forEachEffect(list::add, this.potionDurationScale); - List entitiesOfClass = this.level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox()); - if (!entitiesOfClass.isEmpty()) { -+ List entities = new java.util.ArrayList<>(); // CraftBukkit - for (LivingEntity livingEntity : entitiesOfClass) { - if (!this.victims.containsKey(livingEntity) - && livingEntity.isAffectedByPotions() -@@ -226,6 +_,17 @@ - double d1 = livingEntity.getZ() - this.getZ(); - double d2 = d * d + d1 * d1; - if (d2 <= radius * radius) { +@@ -218,12 +_,24 @@ + this.potionContents.forEachEffect(allEffects::add, this.potionDurationScale); + List entities = this.level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox()); + if (!entities.isEmpty()) { ++ List bukkitEntities = new java.util.ArrayList<>(); // CraftBukkit + for (LivingEntity entity : entities) { + if (!this.victims.containsKey(entity) && entity.isAffectedByPotions() && !allEffects.stream().noneMatch(entity::canBeAffected)) { + double xd = entity.getX() - this.getX(); + double zd = entity.getZ() - this.getZ(); + double dist = xd * xd + zd * zd; + if (dist <= radius * radius) { + // CraftBukkit start -+ entities.add((org.bukkit.entity.LivingEntity) livingEntity.getBukkitEntity()); ++ bukkitEntities.add((org.bukkit.entity.LivingEntity) entity.getBukkitEntity()); + } + } + } -+ org.bukkit.event.entity.AreaEffectCloudApplyEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callAreaEffectCloudApplyEvent(this, entities); ++ org.bukkit.event.entity.AreaEffectCloudApplyEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callAreaEffectCloudApplyEvent(this, bukkitEntities); + if (!event.isCancelled()) { -+ for (org.bukkit.entity.LivingEntity entity : event.getAffectedEntities()) { -+ if (entity instanceof org.bukkit.craftbukkit.entity.CraftLivingEntity) { -+ net.minecraft.world.entity.LivingEntity livingEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity).getHandle(); ++ for (org.bukkit.entity.LivingEntity bukkitLivingEntity : event.getAffectedEntities()) { ++ if (bukkitLivingEntity instanceof org.bukkit.craftbukkit.entity.CraftLivingEntity craftLivingEntity) { ++ LivingEntity entity = craftLivingEntity.getHandle(); + // CraftBukkit end - this.victims.put(livingEntity, this.tickCount + this.reapplicationDelay); + this.victims.put(entity, this.tickCount + this.reapplicationDelay); - for (MobEffectInstance mobEffectInstance : list) { -@@ -234,14 +_,14 @@ + for (MobEffectInstance effect : allEffects) { +@@ -232,14 +_,14 @@ .value() - .applyInstantenousEffect(level, this, this.getOwner(), livingEntity, mobEffectInstance.getAmplifier(), 0.5); + .applyInstantenousEffect(serverLevel, this, this.getOwner(), entity, effect.getAmplifier(), 0.5); } else { -- livingEntity.addEffect(new MobEffectInstance(mobEffectInstance), this); -+ livingEntity.addEffect(new MobEffectInstance(mobEffectInstance), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AREA_EFFECT_CLOUD); // CraftBukkit +- entity.addEffect(new MobEffectInstance(effect), this); ++ entity.addEffect(new MobEffectInstance(effect), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AREA_EFFECT_CLOUD); // CraftBukkit } } @@ -61,7 +60,7 @@ return; } -@@ -251,7 +_,7 @@ +@@ -249,7 +_,7 @@ if (this.durationOnUse != 0 && this.duration != -1) { this.duration = this.duration + this.durationOnUse; if (this.duration <= 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ConversionType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ConversionType.java.patch index 479522aad45a..162fc9103da5 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ConversionType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ConversionType.java.patch @@ -2,18 +2,18 @@ +++ b/net/minecraft/world/entity/ConversionType.java @@ -24,7 +_,7 @@ - for (Entity entity : newMob.getPassengers()) { - entity.stopRiding(); -- entity.remove(Entity.RemovalReason.DISCARDED); -+ entity.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause + for (Entity passenger : to.getPassengers()) { + passenger.stopRiding(); +- passenger.remove(Entity.RemovalReason.DISCARDED); ++ passenger.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause } - firstPassenger.startRiding(newMob); + rootPassenger.startRiding(to); @@ -73,6 +_,7 @@ if (leashHolder != null) { - oldMob.dropLeash(); + from.dropLeash(); } -+ newMob.aware = oldMob.aware; // Paper - Fix nerfed slime when splitting ++ to.aware = from.aware; // Paper - Fix nerfed slime when splitting - this.convertCommon(oldMob, newMob, conversionParams); + this.convertCommon(from, to, params); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index 846f332e554c..e385d875cd33 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -153,6 +_,105 @@ - import org.slf4j.Logger; - - public abstract class Entity implements SyncedDataHolder, DebugValueSource, Nameable, ItemOwner, SlotProvider, EntityAccess, ScoreHolder, DataComponentGetter { +@@ -168,6 +_,105 @@ + SlotProvider, + DebugValueSource, + TypedInstance> { + // CraftBukkit start + private static final int CURRENT_LEVEL = 2; + static boolean isLevelAtLeast(ValueInput input, int level) { @@ -106,7 +106,7 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final String TAG_ID = "id"; public static final String TAG_UUID = "UUID"; -@@ -228,7 +_,7 @@ +@@ -243,7 +_,7 @@ public double yOld; public double zOld; public boolean noPhysics; @@ -114,8 +114,8 @@ + public final RandomSource random = SHARED_RANDOM; // Paper - Share random for entities to make them more random public int tickCount; private int remainingFireTicks; - public boolean wasTouchingWater; -@@ -264,7 +_,7 @@ + private final EntityFluidInteraction fluidInteraction = new EntityFluidInteraction(Set.of(FluidTags.WATER, FluidTags.LAVA)); +@@ -278,7 +_,7 @@ protected UUID uuid = Mth.createInsecureUUID(this.random); protected String stringUUID = this.uuid.toString(); private boolean hasGlowingTag; @@ -124,7 +124,7 @@ private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0}; private long pistonDeltasGameTime; private EntityDimensions dimensions; -@@ -278,6 +_,7 @@ +@@ -292,6 +_,7 @@ public boolean hasVisualFire; private Vec3 lastKnownSpeed = Vec3.ZERO; private @Nullable Vec3 lastKnownPosition; @@ -132,7 +132,7 @@ private @Nullable BlockState inBlockState = null; public static final int MAX_MOVEMENTS_HANDELED_PER_TICK = 100; private final ArrayDeque movementThisTick = new ArrayDeque<>(100); -@@ -285,6 +_,40 @@ +@@ -299,6 +_,40 @@ private final LongSet visitedBlocks = new LongOpenHashSet(); private final InsideBlockEffectApplier.StepBasedCollector insideEffectCollector = new InsideBlockEffectApplier.StepBasedCollector(); private CustomData customData = CustomData.EMPTY; @@ -171,17 +171,17 @@ + } + // Paper end - public Entity(EntityType type, Level level) { + public Entity(final EntityType type, final Level level) { this.type = type; -@@ -306,6 +_,7 @@ - this.entityData = builder.build(); +@@ -320,6 +_,7 @@ + this.entityData = entityDataBuilder.build(); this.setPos(0.0, 0.0, 0.0); this.eyeHeight = this.dimensions.eyeHeight(); + this.despawnTime = level == null || type == EntityType.PLAYER ? -1 : level.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit } - public boolean isColliding(BlockPos pos, BlockState state) { -@@ -318,6 +_,12 @@ + public boolean isColliding(final BlockPos pos, final BlockState state) { +@@ -332,6 +_,12 @@ return team != null && team.getColor().getColor() != null ? team.getColor().getColor() : 16777215; } @@ -194,19 +194,19 @@ public boolean isSpectator() { return false; } -@@ -370,7 +_,7 @@ +@@ -389,7 +_,7 @@ } - public boolean addTag(String tag) { + public boolean addTag(final String tag) { - return this.tags.size() < 1024 && this.tags.add(tag); + return this.tags.add(tag); // Paper - fully limit tag size - replace set impl } - public boolean removeTag(String tag) { -@@ -378,12 +_,18 @@ + public boolean removeTag(final String tag) { +@@ -397,12 +_,18 @@ } - public void kill(ServerLevel level) { + public void kill(final ServerLevel level) { - this.remove(Entity.RemovalReason.KILLED); + this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause this.gameEvent(GameEvent.ENTITY_DIE); @@ -223,47 +223,47 @@ + // CraftBukkit end } - protected abstract void defineSynchedData(SynchedEntityData.Builder builder); -@@ -392,6 +_,48 @@ + protected abstract void defineSynchedData(SynchedEntityData.Builder entityData); +@@ -411,6 +_,48 @@ return this.entityData; } + // CraftBukkit start + public void refreshEntityData(ServerPlayer to) { -+ List> list = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default ++ List> values = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default + + if (to.getBukkitEntity().canSee(this.getBukkitEntity())) { // Paper -+ to.connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket(this.getId(), list)); ++ to.connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket(this.getId(), values)); + } + } + // CraftBukkit end + // Paper start + // This method should only be used if the data of an entity could have become desynced + // due to interactions on the client. -+ public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) { ++ public void resendPossiblyDesyncedEntityData(ServerPlayer player) { + if (player.getBukkitEntity().canSee(this.getBukkitEntity())) { -+ ServerLevel world = (net.minecraft.server.level.ServerLevel)this.level(); -+ net.minecraft.server.level.ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.getId()); ++ ServerLevel level = (net.minecraft.server.level.ServerLevel) this.level(); ++ net.minecraft.server.level.ChunkMap.TrackedEntity tracker = level == null ? null : level.getChunkSource().chunkMap.entityMap.get(this.getId()); + if (tracker == null) { + return; + } -+ final net.minecraft.server.level.ServerEntity serverEntity = tracker.serverEntity; -+ final List> list = new java.util.ArrayList<>(); ++ final ServerEntity serverEntity = tracker.serverEntity; ++ final List> list = new ArrayList<>(); + serverEntity.sendPairingData(player, list::add); + player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list)); + } + } + -+ // This method allows you to specifically resend certain data accessor keys to the client -+ public void resendPossiblyDesyncedDataValues(List> keys, ServerPlayer to) { ++ // This method allows you to specifically resend certain data accessors to the client ++ public void resendPossiblyDesyncedDataValues(List> accessors, ServerPlayer to) { + if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) { + return; + } + -+ final List> values = new java.util.ArrayList<>(keys.size()); -+ for (final EntityDataAccessor key : keys) { -+ final SynchedEntityData.DataItem synchedValue = this.entityData.getItem(key); -+ values.add(synchedValue.value()); ++ final List> values = new ArrayList<>(accessors.size()); ++ for (final EntityDataAccessor accessor : accessors) { ++ final SynchedEntityData.DataItem item = this.entityData.getItem(accessor); ++ values.add(item.value()); + } + + to.connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket(this.id, values)); @@ -271,27 +271,27 @@ + // Paper end + @Override - public boolean equals(Object other) { - return other instanceof Entity && ((Entity)other).id == this.id; -@@ -403,7 +_,13 @@ + public boolean equals(final Object obj) { + return obj instanceof Entity && ((Entity)obj).id == this.id; +@@ -422,7 +_,13 @@ } - public void remove(Entity.RemovalReason reason) { + public void remove(final Entity.RemovalReason reason) { - this.setRemoved(reason); + // CraftBukkit start - add Bukkit remove cause + this.remove(reason, null); + } + -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { + this.setRemoved(reason, eventCause); + // CraftBukkit end } public void onClientRemoval() { -@@ -413,6 +_,15 @@ +@@ -432,6 +_,15 @@ } - public void setPose(Pose pose) { + public void setPose(final Pose pose) { + if (this.fixedPose) return; // Paper - Expand Pose API + // CraftBukkit start + if (pose == this.getPose()) { @@ -304,11 +304,13 @@ this.entityData.set(DATA_POSE, pose); } -@@ -436,6 +_,32 @@ +@@ -454,7 +_,33 @@ + return Mth.lengthSquared(dx, dz) < Mth.square(distanceXZ) && Mth.square(dy) < Mth.square(distanceY); } - public void setRot(float yRot, float xRot) { -+ // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0 +- public void setRot(final float yRot, final float xRot) { ++ // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0 ++ public void setRot(float yRot, float xRot) { + if (Float.isNaN(yRot)) { + yRot = 0; + } @@ -337,10 +339,10 @@ this.setYRot(yRot % 360.0F); this.setXRot(xRot % 360.0F); } -@@ -445,8 +_,8 @@ +@@ -464,8 +_,8 @@ } - public void setPos(double x, double y, double z) { + public void setPos(final double x, final double y, final double z) { - this.setPosRaw(x, y, z); - this.setBoundingBox(this.makeBoundingBox()); + this.setPosRaw(x, y, z, true); // Paper - Block invalid positions and bounding box; force update @@ -348,7 +350,7 @@ } protected final AABB makeBoundingBox() { -@@ -480,12 +_,28 @@ +@@ -499,12 +_,28 @@ } public void tick() { @@ -371,13 +373,13 @@ + // CraftBukkit end + public void baseTick() { - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("entityBaseTick"); -+ if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups + ProfilerFiller profiler = Profiler.get(); + profiler.push("entityBaseTick"); ++ if (this.firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(this.level); // Paper - Prevent entity loading causing async lookups this.computeSpeed(); this.inBlockState = null; if (this.isPassenger() && this.getVehicle().isRemoved()) { -@@ -496,7 +_,7 @@ +@@ -515,7 +_,7 @@ this.boardingCooldown--; } @@ -386,7 +388,7 @@ if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } -@@ -524,6 +_,10 @@ +@@ -543,6 +_,10 @@ if (this.isInLava()) { this.fallDistance *= 0.5; @@ -397,12 +399,12 @@ } this.checkBelowWorld(); -@@ -549,11 +_,16 @@ +@@ -568,11 +_,16 @@ } - public void setSharedFlagOnFire(boolean isOnFire) { -- this.setSharedFlag(FLAG_ONFIRE, isOnFire || this.hasVisualFire); -+ this.setSharedFlag(FLAG_ONFIRE, this.visualFire.toBooleanOrElse(isOnFire)); // Paper - improve visual fire API + public void setSharedFlagOnFire(final boolean value) { +- this.setSharedFlag(FLAG_ONFIRE, value || this.hasVisualFire); ++ this.setSharedFlag(FLAG_ONFIRE, this.visualFire.toBooleanOrElse(value)); // Paper - improve visual fire API } public void checkBelowWorld() { @@ -416,7 +418,7 @@ this.onBelowWorld(); } } -@@ -581,15 +_,41 @@ +@@ -600,15 +_,41 @@ } public void lavaIgnite() { @@ -460,28 +462,28 @@ && this.shouldPlayLavaHurtSound() && !this.isSilent()) { serverLevel.playSound( -@@ -604,6 +_,20 @@ +@@ -623,6 +_,20 @@ } - public final void igniteForSeconds(float seconds) { + public final void igniteForSeconds(final float numberOfSeconds) { + // CraftBukkit start -+ this.igniteForSeconds(seconds, true); ++ this.igniteForSeconds(numberOfSeconds, true); + } + -+ public final void igniteForSeconds(float seconds, boolean callEvent) { ++ public final void igniteForSeconds(float numberOfSeconds, final boolean callEvent) { + if (callEvent) { -+ org.bukkit.event.entity.EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustEvent(this.getBukkitEntity(), seconds); ++ org.bukkit.event.entity.EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustEvent(this.getBukkitEntity(), numberOfSeconds); + if (!event.callEvent()) { + return; + } + -+ seconds = event.getDuration(); ++ numberOfSeconds = event.getDuration(); + } + // CraftBukkit end - this.igniteForTicks(Mth.floor(seconds * 20.0F)); + this.igniteForTicks(Mth.floor(numberOfSeconds * 20.0F)); } -@@ -628,7 +_,7 @@ +@@ -647,7 +_,7 @@ } protected void onBelowWorld() { @@ -489,8 +491,8 @@ + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.OUT_OF_WORLD); // CraftBukkit - add Bukkit remove cause } - public boolean isFree(double x, double y, double z) { -@@ -684,7 +_,28 @@ + public boolean isFree(final double xa, final double ya, final double za) { +@@ -703,7 +_,28 @@ return this.onGround; } @@ -504,23 +506,23 @@ + private double moveStartZ; + // Paper end - detailed watchdog information + - public void move(MoverType type, Vec3 movement) { -+ final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity + public void move(final MoverType moverType, Vec3 delta) { ++ final Vec3 originalMovement = delta; // Paper - Expose pre-collision velocity + // Paper start - detailed watchdog information + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); + synchronized (this.posLock) { + this.moveStartX = this.getX(); + this.moveStartY = this.getY(); + this.moveStartZ = this.getZ(); -+ this.moveVector = movement; ++ this.moveVector = delta; + } + try { + // Paper end - detailed watchdog information if (this.noPhysics) { - this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + this.setPos(this.getX() + delta.x, this.getY() + delta.y, this.getZ() + delta.z); this.horizontalCollision = false; -@@ -767,6 +_,27 @@ - block.updateEntityMovementAfterFallOn(this.level(), this); +@@ -786,6 +_,27 @@ + onBlock.updateEntityMovementAfterFallOn(this.level(), this); } } + // CraftBukkit start @@ -528,13 +530,13 @@ + org.bukkit.entity.Vehicle vehicle = (org.bukkit.entity.Vehicle) this.getBukkitEntity(); + org.bukkit.block.Block block = this.level.getWorld().getBlockAt(Mth.floor(this.getX()), Mth.floor(this.getY()), Mth.floor(this.getZ())); + -+ if (movement.x > vec3.x) { ++ if (delta.x > movement.x) { + block = block.getRelative(org.bukkit.block.BlockFace.EAST); -+ } else if (movement.x < vec3.x) { ++ } else if (delta.x < movement.x) { + block = block.getRelative(org.bukkit.block.BlockFace.WEST); -+ } else if (movement.z > vec3.z) { ++ } else if (delta.z > movement.z) { + block = block.getRelative(org.bukkit.block.BlockFace.SOUTH); -+ } else if (movement.z < vec3.z) { ++ } else if (delta.z < movement.z) { + block = block.getRelative(org.bukkit.block.BlockFace.NORTH); + } + @@ -546,9 +548,9 @@ + // CraftBukkit end if (!this.level().isClientSide() || this.isLocalInstanceAuthoritative()) { - Entity.MovementEmission movementEmission = this.getMovementEmission(); -@@ -780,6 +_,13 @@ - profilerFiller.pop(); + Entity.MovementEmission emission = this.getMovementEmission(); +@@ -799,6 +_,13 @@ + profiler.pop(); } } + // Paper start - detailed watchdog information @@ -560,51 +562,51 @@ + // Paper end - detailed watchdog information } - private void applyMovementEmissionAndPlaySound(Entity.MovementEmission movementEmission, Vec3 movement, BlockPos pos, BlockState state) { -@@ -965,7 +_,7 @@ + private void applyMovementEmissionAndPlaySound( +@@ -994,7 +_,7 @@ } - protected BlockPos getOnPos(float yOffset) { + protected BlockPos getOnPos(final float offset) { - if (this.mainSupportingBlockPos.isPresent()) { + if (this.mainSupportingBlockPos.isPresent() && this.level().getChunkIfLoadedImmediately(this.mainSupportingBlockPos.get()) != null) { // Paper - ensure no loads - BlockPos blockPos = this.mainSupportingBlockPos.get(); - if (!(yOffset > 1.0E-5F)) { - return blockPos; -@@ -1220,7 +_,7 @@ - if (flag2) { + BlockPos getOnPos = this.mainSupportingBlockPos.get(); + if (!(offset > 1.0E-5F)) { + return getOnPos; +@@ -1263,7 +_,7 @@ + if (insideBlock) { try { - boolean flag4 = flag || aabb.intersects(pos); -- stepBasedCollector.advanceStep(index); -+ stepBasedCollector.advanceStep(index, pos); // Paper - track position inside effect was triggered on - blockState.entityInside(this.level(), pos, this, stepBasedCollector, flag4); - this.onInsideBlock(blockState); + boolean isPrecise = movedFar || deflatedBoundingBoxAtTarget.intersects(blockIntersection); +- effectCollector.advanceStep(iteration); ++ effectCollector.advanceStep(iteration, blockIntersection); // Paper - track position inside effect was triggered on + state.entityInside(this.level(), blockIntersection, this, effectCollector, isPrecise); + this.onInsideBlock(state); } catch (Throwable var20) { -@@ -1234,7 +_,7 @@ +@@ -1277,7 +_,7 @@ } - if (flag3) { -- stepBasedCollector.advanceStep(index); -+ stepBasedCollector.advanceStep(index, pos); // Paper - track position inside effect was triggered on - blockState.getFluidState().entityInside(this.level(), pos, this, stepBasedCollector); + if (insideFluid) { +- effectCollector.advanceStep(iteration); ++ effectCollector.advanceStep(iteration, blockIntersection); // Paper - track position inside effect was triggered on + state.getFluidState().entityInside(this.level(), blockIntersection, this, effectCollector); } -@@ -1670,6 +_,7 @@ +@@ -1690,6 +_,7 @@ this.setXRot(Mth.clamp(xRot, -90.0F, 90.0F) % 360.0F); this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); + this.setYHeadRot(yRot); // Paper - Update head rotation } - public void absSnapTo(double x, double y, double z) { -@@ -1679,6 +_,7 @@ + public void absSnapTo(final double x, final double y, final double z) { +@@ -1699,6 +_,7 @@ this.yo = y; - this.zo = d1; - this.setPos(d, y, d1); + this.zo = cz; + this.setPos(cx, y, cz); + if (this.valid) this.level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit } - public void snapTo(Vec3 pos) { -@@ -1703,6 +_,7 @@ + public void snapTo(final Vec3 pos) { +@@ -1723,6 +_,7 @@ this.setXRot(xRot); this.setOldPosAndRot(); this.reapplyPosition(); @@ -612,28 +614,28 @@ } public final void setOldPosAndRot() { -@@ -1769,6 +_,7 @@ - public void push(Entity entity) { +@@ -1789,6 +_,7 @@ + public void push(final Entity entity) { if (!this.isPassengerOfSameVehicle(entity)) { if (!entity.noPhysics && !this.noPhysics) { + if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper - Collision option for requiring a player participant - double d = entity.getX() - this.getX(); - double d1 = entity.getZ() - this.getZ(); - double max = Mth.absMax(d, d1); -@@ -1804,8 +_,24 @@ + double xa = entity.getX() - this.getX(); + double za = entity.getZ() - this.getZ(); + double dd = Mth.absMax(xa, za); +@@ -1824,8 +_,24 @@ } - public void push(double x, double y, double z) { + public void push(final double xa, final double ya, final double za) { + // Paper start - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent -+ this.push(x, y, z, null); ++ this.push(xa, ya, za, null); + } + -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { ++ public void push(final double xa, final double ya, final double za, @Nullable Entity pushingEntity) { + // Paper end - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - if (Double.isFinite(x) && Double.isFinite(y) && Double.isFinite(z)) { -- this.setDeltaMovement(this.getDeltaMovement().add(x, y, z)); + if (Double.isFinite(xa) && Double.isFinite(ya) && Double.isFinite(za)) { +- this.setDeltaMovement(this.getDeltaMovement().add(xa, ya, za)); + // Paper start - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent -+ org.bukkit.util.Vector delta = new org.bukkit.util.Vector(x, y, z); ++ org.bukkit.util.Vector delta = new org.bukkit.util.Vector(xa, ya, za); + if (pushingEntity != null) { + io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent event = new io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent(this.getBukkitEntity(), io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.PUSH, pushingEntity.getBukkitEntity(), delta); + if (!event.callEvent()) { @@ -646,7 +648,7 @@ this.needsSync = true; } } -@@ -1913,8 +_,20 @@ +@@ -1932,8 +_,20 @@ } public boolean isPushable() { @@ -665,46 +667,46 @@ + } + // CraftBukkit end - public void awardKillScore(Entity entity, DamageSource damageSource) { - if (entity instanceof ServerPlayer) { -@@ -1941,15 +_,23 @@ + public void awardKillScore(final Entity victim, final DamageSource killingBlow) { + if (victim instanceof ServerPlayer) { +@@ -1960,15 +_,23 @@ } - public boolean saveAsPassenger(ValueOutput output) { + public boolean saveAsPassenger(final ValueOutput output) { - if (this.removalReason != null && !this.removalReason.shouldSave()) { + // CraftBukkit start - allow excluding certain data when saving + // Paper start - Raw entity serialization API + return this.saveAsPassenger(output, true, false, false); + } + -+ public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { ++ public boolean saveAsPassenger(final ValueOutput output, final boolean includeAll, final boolean includeNonSaveable, final boolean forceSerialization) { + // Paper end - Raw entity serialization API + // CraftBukkit end + if (this.removalReason != null && !this.removalReason.shouldSave() && !forceSerialization) { // Paper - Raw entity serialization API return false; } else { -- String encodeId = this.getEncodeId(); -- if (encodeId == null) { -+ String encodeId = this.getEncodeId(includeNonSaveable); // Paper - Raw entity serialization API -+ if ((!this.persist && !forceSerialization) || encodeId == null) { // CraftBukkit - persist flag // Paper - Raw entity serialization API +- String id = this.getEncodeId(); +- if (id == null) { ++ String id = this.getEncodeId(includeNonSaveable); // Paper - Raw entity serialization API ++ if ((!this.persist && !forceSerialization) || id == null) { // CraftBukkit - persist flag // Paper - Raw entity serialization API return false; } else { - output.putString("id", encodeId); + output.putString("id", id); - this.saveWithoutId(output); -+ this.saveWithoutId(output , includeAll, includeNonSaveable, forceSerialization); // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API ++ this.saveWithoutId(output, includeAll, includeNonSaveable, forceSerialization); // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API return true; } } -@@ -1960,14 +_,34 @@ +@@ -1979,14 +_,34 @@ } - public void saveWithoutId(ValueOutput output) { + public void saveWithoutId(final ValueOutput output) { + // CraftBukkit start - allow excluding certain data when saving + // Paper start - Raw entity serialization API + this.saveWithoutId(output, true, false, false); + } + -+ public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { ++ public void saveWithoutId(final ValueOutput output, final boolean includeAll, final boolean includeNonSaveable, final boolean forceSerialization) { + // Paper end - Raw entity serialization API + // CraftBukkit end try { @@ -730,7 +732,7 @@ output.store("Rotation", Vec2.CODEC, new Vec2(this.getYRot(), this.getXRot())); output.putDouble("fall_distance", this.fallDistance); output.putShort("Fire", (short)this.remainingFireTicks); -@@ -1975,7 +_,29 @@ +@@ -1994,7 +_,29 @@ output.putBoolean("OnGround", this.onGround()); output.putBoolean("Invulnerable", this.invulnerable); output.putInt("PortalCooldown", this.portalCooldown); @@ -760,7 +762,7 @@ output.storeNullable("CustomName", ComponentSerialization.CODEC, this.getCustomName()); if (this.isCustomNameVisible()) { output.putBoolean("CustomNameVisible", this.isCustomNameVisible()); -@@ -1998,9 +_,14 @@ +@@ -2017,9 +_,14 @@ output.putInt("TicksFrozen", this.getTicksFrozen()); } @@ -778,23 +780,23 @@ if (!this.tags.isEmpty()) { output.store("Tags", TAG_LIST_CODEC, List.copyOf(this.tags)); -@@ -2010,13 +_,13 @@ +@@ -2029,13 +_,13 @@ output.store("data", CustomData.CODEC, this.customData); } - this.addAdditionalSaveData(output); + this.addAdditionalSaveData(output, includeAll); // CraftBukkit - pass on includeAll if (this.isVehicle()) { - ValueOutput.ValueOutputList valueOutputList = output.childrenList("Passengers"); + ValueOutput.ValueOutputList passengersList = output.childrenList("Passengers"); - for (Entity entity : this.getPassengers()) { - ValueOutput valueOutput = valueOutputList.addChild(); -- if (!entity.saveAsPassenger(valueOutput)) { -+ if (!entity.saveAsPassenger(valueOutput, includeAll, includeNonSaveable, forceSerialization)) { // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API - valueOutputList.discardLast(); + for (Entity passenger : this.getPassengers()) { + ValueOutput passengerOutput = passengersList.addChild(); +- if (!passenger.saveAsPassenger(passengerOutput)) { ++ if (!passenger.saveAsPassenger(passengerOutput, includeAll, includeNonSaveable, forceSerialization)) { // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API + passengersList.discardLast(); } } -@@ -2025,6 +_,34 @@ +@@ -2044,6 +_,34 @@ output.discard("Passengers"); } } @@ -827,9 +829,9 @@ + } + // Paper end } catch (Throwable var7) { - CrashReport crashReport = CrashReport.forThrowable(var7, "Saving entity NBT"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being saved"); -@@ -2068,7 +_,20 @@ + CrashReport report = CrashReport.forThrowable(var7, "Saving entity NBT"); + CrashReportCategory category = report.addCategory("Entity being saved"); +@@ -2089,7 +_,20 @@ this.setNoGravity(input.getBooleanOr("NoGravity", false)); this.setGlowingTag(input.getBooleanOr("Glowing", false)); this.setTicksFrozen(input.getIntOr("TicksFrozen", 0)); @@ -851,7 +853,7 @@ this.customData = input.read("data", CustomData.CODEC).orElse(CustomData.EMPTY); this.tags.clear(); input.read("Tags", TAG_LIST_CODEC).ifPresent(this.tags::addAll); -@@ -2079,6 +_,59 @@ +@@ -2100,6 +_,59 @@ } else { throw new IllegalStateException("Entity has invalid rotation"); } @@ -909,22 +911,24 @@ + freezeLocked = input.getBooleanOr("Paper.FreezeLock", false); + // Paper end } catch (Throwable var7) { - CrashReport crashReport = CrashReport.forThrowable(var7, "Loading entity NBT"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being loaded"); -@@ -2092,13 +_,24 @@ + CrashReport report = CrashReport.forThrowable(var7, "Loading entity NBT"); + CrashReportCategory category = report.addCategory("Entity being loaded"); +@@ -2113,7 +_,13 @@ } public final @Nullable String getEncodeId() { +- if (!this.getType().canSerialize()) { + // Paper start - Raw entity serialization API -+ return getEncodeId(false); ++ return this.getEncodeId(false); + } -+ public final @Nullable String getEncodeId(boolean includeNonSaveable) { -+ // Paper end - Raw entity serialization API - EntityType type = this.getType(); - Identifier key = EntityType.getKey(type); -- return !type.canSerialize() ? null : key.toString(); -+ return (type.canSerialize() || includeNonSaveable) ? key.toString() : null; // Paper - Raw entity serialization API - } ++ ++ public final @Nullable String getEncodeId(final boolean includeNonSaveable) { ++ if (!includeNonSaveable && !this.getType().canSerialize()) { ++ // Paper end - Raw entity serialization API + return null; + } else { + ResourceKey> typeId = this.typeHolder().unwrapKey().orElseThrow(() -> new IllegalStateException("Unregistered entity")); +@@ -2123,6 +_,12 @@ protected abstract void readAdditionalSaveData(ValueInput input); @@ -936,13 +940,13 @@ + protected abstract void addAdditionalSaveData(ValueOutput output); - public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemLike item) { -@@ -2110,11 +_,58 @@ + public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemLike resource) { +@@ -2134,11 +_,59 @@ } - public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemStack stack, Vec3 offset) { + public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemStack itemStack, final Vec3 offset) { + // Paper start - Restore vanilla drops behavior -+ return this.spawnAtLocation(level, stack, offset, null); ++ return this.spawnAtLocation(level, itemStack, offset, null); + } + + public record DefaultDrop(Item item, org.bukkit.inventory.ItemStack stack, java.util.function.@Nullable Consumer dropConsumer) { @@ -959,80 +963,81 @@ + } + } + -+ public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemStack stack, Vec3 offset, java.util.function.@Nullable Consumer delayedAddConsumer) { ++ public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemStack itemStack, final Vec3 offset, java.util.function.@Nullable Consumer delayedAddConsumer) { + // Paper end - Restore vanilla drops behavior - if (stack.isEmpty()) { + if (itemStack.isEmpty()) { return null; } else { + // CraftBukkit start - Capture drops for death event + if (this instanceof net.minecraft.world.entity.LivingEntity && !this.forceDrops) { + // Paper start - Restore vanilla drops behavior -+ ((net.minecraft.world.entity.LivingEntity) this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(stack, itemStack -> { -+ ItemEntity itemEntity = new ItemEntity(this.level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, itemStack); // stack is copied before consumer -+ itemEntity.setDefaultPickUpDelay(); -+ this.level.addFreshEntity(itemEntity); -+ if (delayedAddConsumer != null) delayedAddConsumer.accept(itemEntity); ++ ((net.minecraft.world.entity.LivingEntity)this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(itemStack, dropStack -> { ++ ItemEntity dropEntity = new ItemEntity(this.level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, dropStack); // stack is copied before consumer ++ dropEntity.setDefaultPickUpDelay(); ++ this.level.addFreshEntity(dropEntity); ++ if (delayedAddConsumer != null) delayedAddConsumer.accept(dropEntity); + })); + // Paper end - Restore vanilla drops behavior + return null; + } + // CraftBukkit end - ItemEntity itemEntity = new ItemEntity(level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, stack); -- itemEntity.setDefaultPickUpDelay(); -+ itemEntity.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) + ItemEntity entity = new ItemEntity(level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, itemStack); +- entity.setDefaultPickUpDelay(); ++ entity.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) + // Paper start - Call EntityDropItemEvent -+ return this.spawnAtLocation(level, itemEntity); ++ return this.spawnAtLocation(level, entity); + } + } -+ public @Nullable ItemEntity spawnAtLocation(ServerLevel level, ItemEntity itemEntity) { ++ ++ public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemEntity entity) { ++ // Paper end - Call EntityDropItemEvent ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entity.getBukkitEntity()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return null; ++ } ++ // CraftBukkit end + { -+ // Paper end - Call EntityDropItemEvent -+ // CraftBukkit start -+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); -+ org.bukkit.Bukkit.getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ return null; -+ } -+ // CraftBukkit end - level.addFreshEntity(itemEntity); - return itemEntity; + level.addFreshEntity(entity); + return entity; } -@@ -2159,6 +_,15 @@ +@@ -2183,6 +_,15 @@ - for (Leashable leashable1 : list) { - if (leashable1.canHaveALeashAttachedTo(this)) { + for (Leashable mob : mobsToLeash) { + if (mob.canHaveALeashAttachedTo(this)) { + // Paper start - PlayerLeashEvent + final org.bukkit.event.entity.PlayerLeashEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent( -+ leashable1, ++ mob, + this, + player, + hand + ); + if (event != null && event.isCancelled()) continue; // If the event was called and cancelled, skip this. + // Paper end - PlayerLeashEvent - leashable1.setLeashedTo(this, true); - flag = true; + mob.setLeashedTo(this, true); + anyLeashed = true; } -@@ -2173,7 +_,7 @@ +@@ -2197,7 +_,7 @@ } - ItemStack itemInHand = player.getItemInHand(hand); -- if (itemInHand.is(Items.SHEARS) && this.shearOffAllLeashConnections(player)) { -+ if (itemInHand.is(Items.SHEARS) && this.shearOffAllLeashConnections(player, hand)) { // Paper - PlayerUnleashEntityEvent - pass used hand - itemInHand.hurtAndBreak(1, player, hand); + ItemStack heldItem = player.getItemInHand(hand); +- if (heldItem.is(Items.SHEARS) && this.shearOffAllLeashConnections(player)) { ++ if (heldItem.is(Items.SHEARS) && this.shearOffAllLeashConnections(player, hand)) { // Paper - PlayerUnleashEntityEvent - pass used hand + heldItem.hurtAndBreak(1, player, hand); return InteractionResult.SUCCESS; - } else if (this instanceof Mob mob -@@ -2186,11 +_,13 @@ - if (this.isAlive() && this instanceof Leashable leashable2) { - if (leashable2.getLeashHolder() == player) { + } else if (this instanceof Mob target +@@ -2210,11 +_,13 @@ + if (this.isAlive() && this instanceof Leashable leashablex) { + if (leashablex.getLeashHolder() == player) { if (!this.level().isClientSide()) { - if (player.hasInfiniteMaterials()) { -- leashable2.removeLeash(); +- leashablex.removeLeash(); - } else { -- leashable2.dropLeash(); +- leashablex.dropLeash(); + // Paper start - EntityUnleashEvent + if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( -+ leashable2, player, hand, !player.hasInfiniteMaterials(), true ++ leashablex, player, hand, !player.hasInfiniteMaterials(), true + )) { + return InteractionResult.PASS; } @@ -1040,118 +1045,120 @@ this.gameEvent(GameEvent.ENTITY_INTERACT, player); this.playSound(SoundEvents.LEAD_UNTIED); -@@ -2207,9 +_,22 @@ +@@ -2231,9 +_,22 @@ - if (leashable2.canHaveALeashAttachedTo(player)) { - if (leashable2.isLeashed()) { -- leashable2.dropLeash(); + if (leashablex.canHaveALeashAttachedTo(player)) { + if (leashablex.isLeashed()) { +- leashablex.dropLeash(); + // Paper start - EntityUnleashEvent + if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( -+ leashable2, player, hand, true, true ++ leashablex, player, hand, true, true + )) { + return InteractionResult.PASS; + } + // Paper end - EntityUnleashEvent -+ // leashable2.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent ++ // leashablex.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent } + // Paper start - EntityLeashEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(this, player, player, hand).isCancelled()) { -+ ((ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(this, leashable2.getLeashHolder())); ++ ((ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(this, leashablex.getLeashHolder())); + return InteractionResult.PASS; + } + // Paper end - EntityLeashEvent - leashable2.setLeashedTo(player, true); + leashablex.setLeashedTo(player, true); this.playSound(SoundEvents.LEAD_TIED); - itemInHand1.shrink(1); -@@ -2223,7 +_,12 @@ + itemStack.shrink(1); +@@ -2247,7 +_,13 @@ } - public boolean shearOffAllLeashConnections(@Nullable Player player) { -- boolean flag = this.dropAllLeashConnections(player); -+ // Paper start - EntityUnleashEvent - overload + public boolean shearOffAllLeashConnections(final @Nullable Player player) { +- boolean dropped = this.dropAllLeashConnections(player); ++ // Paper start - EntityUnleashEvent - overload + return this.shearOffAllLeashConnections(player, null); + } -+ public boolean shearOffAllLeashConnections(@Nullable Player player, @Nullable InteractionHand interactionHand) { -+ // Paper end - EntityUnleashEvent - overload -+ boolean flag = this.dropAllLeashConnections(player, interactionHand); // Paper - EntityUnleashEvent - overload - if (flag && this.level() instanceof ServerLevel serverLevel) { ++ ++ public boolean shearOffAllLeashConnections(final @Nullable Player player, final @Nullable InteractionHand hand) { ++ // Paper end - EntityUnleashEvent - overload ++ boolean dropped = this.dropAllLeashConnections(player, hand); // Paper - EntityUnleashEvent - overload + if (dropped && this.level() instanceof ServerLevel serverLevel) { serverLevel.playSound(null, this.blockPosition(), SoundEvents.SHEARS_SNIP, player != null ? player.getSoundSource() : this.getSoundSource()); } -@@ -2232,15 +_,38 @@ +@@ -2256,15 +_,39 @@ } - public boolean dropAllLeashConnections(@Nullable Player player) { -+ // Paper start - EntityUnleashEvent - overload -+ return dropAllLeashConnections(player, null); + public boolean dropAllLeashConnections(final @Nullable Player player) { ++ // Paper start - EntityUnleashEvent - overload ++ return this.dropAllLeashConnections(player, null); + } -+ public boolean dropAllLeashConnections(@Nullable Player player, @Nullable InteractionHand interactionHand) { -+ // Paper start - EntityUnleashEvent - overload - List list = Leashable.leashableLeashedTo(this); -- boolean flag = !list.isEmpty(); -+ boolean flag = false; // Paper - EntityUnleashEvent - compute flag later, events might prevent unleashing all connected leashables. - if (this instanceof Leashable leashable && leashable.isLeashed()) { -- leashable.dropLeash(); -- flag = true; ++ ++ public boolean dropAllLeashConnections(final @Nullable Player player, final @Nullable InteractionHand hand) { ++ // Paper end - EntityUnleashEvent - overload + List leashables = Leashable.leashableLeashedTo(this); +- boolean dropped = !leashables.isEmpty(); ++ boolean dropped = false; // Paper - EntityUnleashEvent - compute flag later, events might prevent unleashing all connected leashables. + if (this instanceof Leashable leashableThis && leashableThis.isLeashed()) { +- leashableThis.dropLeash(); +- dropped = true; + // Paper start - EntityUnleashEvent -+ flag |= org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( ++ dropped |= org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( + this, + player, -+ interactionHand, ++ hand, + true, + true + ); + // Paper end - EntityUnleashEvent -+ // leashable.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent -+ // flag = true; // Paper - EntityUnleashEvent - moved above ++ // leashableThis.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent ++ // dropped = true; // Paper - EntityUnleashEvent - moved above } - for (Leashable leashable1 : list) { -- leashable1.dropLeash(); + for (Leashable leashable : leashables) { +- leashable.dropLeash(); + // Paper start - EntityUnleashEvent -+ flag |= org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( // Update flag here, if any entity was unleashed, set to true. -+ leashable1, ++ dropped |= org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( // Update flag here, if any entity was unleashed, set to true. ++ leashable, + player, -+ interactionHand, ++ hand, + true, + true + ); -+ // leashable1.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent ++ // leashable.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent + // Paper end - EntityUnleashEvent } - if (flag) { -@@ -2264,7 +_,9 @@ + if (dropped) { +@@ -2288,7 +_,9 @@ this.gameEvent(GameEvent.SHEAR, player); this.playSound(equippable.shearingSound().value()); if (this.level() instanceof ServerLevel serverLevel) { + this.forceDrops = true; // Paper - this.spawnAtLocation(serverLevel, itemBySlot, average); + this.spawnAtLocation(serverLevel, itemStack, equipmentSpawnOffset); + this.forceDrops = false; // Paper - CriteriaTriggers.PLAYER_SHEARED_EQUIPMENT.trigger((ServerPlayer)player, itemBySlot, mob); + CriteriaTriggers.PLAYER_SHEARED_EQUIPMENT.trigger((ServerPlayer)player, itemStack, target); } -@@ -2337,11 +_,11 @@ +@@ -2356,11 +_,11 @@ } - public boolean startRiding(Entity entity, boolean force, boolean triggerEvents) { -- if (entity == this.vehicle) { -+ if (entity == this.vehicle || entity.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins) + public boolean startRiding(final Entity entityToRide, final boolean force, final boolean sendEventAndTriggers) { +- if (entityToRide == this.vehicle) { ++ if (entityToRide == this.vehicle || entityToRide.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins) return false; - } else if (!entity.couldAcceptPassenger()) { + } else if (!entityToRide.couldAcceptPassenger()) { return false; -- } else if (!this.level().isClientSide() && !entity.type.canSerialize()) { -+ } else if (!force && !this.level().isClientSide() && !entity.type.canSerialize()) { // SPIGOT-7947: Allow force riding all entities +- } else if (!this.level().isClientSide() && !entityToRide.type.canSerialize()) { ++ } else if (!force && !this.level().isClientSide() && !entityToRide.type.canSerialize()) { // SPIGOT-7947: Allow force riding all entities return false; } else { - for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) { -@@ -2351,6 +_,27 @@ + for (Entity vehicleEntity = entityToRide; vehicleEntity.vehicle != null; vehicleEntity = vehicleEntity.vehicle) { +@@ -2370,6 +_,27 @@ } - if (force || this.canRide(entity) && entity.canAddPassenger(this)) { + if (force || this.canRide(entityToRide) && entityToRide.canAddPassenger(this)) { + // CraftBukkit start -+ if (entity.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && this.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { -+ org.bukkit.event.vehicle.VehicleEnterEvent event = new org.bukkit.event.vehicle.VehicleEnterEvent((org.bukkit.entity.Vehicle) entity.getBukkitEntity(), this.getBukkitEntity()); ++ if (entityToRide.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && this.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { ++ org.bukkit.event.vehicle.VehicleEnterEvent event = new org.bukkit.event.vehicle.VehicleEnterEvent((org.bukkit.entity.Vehicle) entityToRide.getBukkitEntity(), this.getBukkitEntity()); + // Suppress during worldgen + if (this.valid) { + org.bukkit.Bukkit.getPluginManager().callEvent(event); @@ -1161,7 +1168,7 @@ + } + } + -+ org.bukkit.event.entity.EntityMountEvent event = new org.bukkit.event.entity.EntityMountEvent(this.getBukkitEntity(), entity.getBukkitEntity()); ++ org.bukkit.event.entity.EntityMountEvent event = new org.bukkit.event.entity.EntityMountEvent(this.getBukkitEntity(), entityToRide.getBukkitEntity()); + // Suppress during worldgen + if (this.valid) { + org.bukkit.Bukkit.getPluginManager().callEvent(event); @@ -1173,7 +1180,7 @@ if (this.isPassenger()) { this.stopRiding(); } -@@ -2383,10 +_,16 @@ +@@ -2402,10 +_,16 @@ } public void removeVehicle() { @@ -1184,14 +1191,14 @@ + public void removeVehicle(boolean suppressCancellation) { + // Paper end - Force entity dismount during teleportation if (this.vehicle != null) { - Entity entity = this.vehicle; + Entity oldVehicle = this.vehicle; this.vehicle = null; -- entity.removePassenger(this); -+ if (!entity.removePassenger(this, suppressCancellation)) this.vehicle = entity; // CraftBukkit // Paper - Force entity dismount during teleportation +- oldVehicle.removePassenger(this); ++ if (!oldVehicle.removePassenger(this, suppressCancellation)) this.vehicle = oldVehicle; // CraftBukkit // Paper - Force entity dismount during teleportation Entity.RemovalReason removalReason = this.getRemovalReason(); if (removalReason == null || removalReason.shouldDestroy()) { - this.level().gameEvent(this, GameEvent.ENTITY_DISMOUNT, entity.position); -@@ -2395,7 +_,13 @@ + this.level().gameEvent(this, GameEvent.ENTITY_DISMOUNT, oldVehicle.position); +@@ -2414,7 +_,13 @@ } public void stopRiding() { @@ -1205,17 +1212,18 @@ + // Paper end - Force entity dismount during teleportation } - protected void addPassenger(Entity passenger) { -@@ -2417,10 +_,43 @@ + protected void addPassenger(final Entity passenger) { +@@ -2436,10 +_,44 @@ } } -- protected void removePassenger(Entity passenger) { +- protected void removePassenger(final Entity passenger) { + // Paper start - Force entity dismount during teleportation -+ protected boolean removePassenger(Entity passenger) { -+ return removePassenger(passenger, false); ++ protected boolean removePassenger(final Entity passenger) { ++ return this.removePassenger(passenger, false); + } -+ protected boolean removePassenger(Entity passenger, boolean suppressCancellation) { // CraftBukkit ++ ++ protected boolean removePassenger(final Entity passenger, final boolean suppressCancellation) { // CraftBukkit + // Paper end - Force entity dismount during teleportation if (passenger.getVehicle() == this) { throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); @@ -1251,15 +1259,15 @@ if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { this.passengers = ImmutableList.of(); } else { -@@ -2429,6 +_,7 @@ +@@ -2448,6 +_,7 @@ passenger.boardingCooldown = 60; } + return true; // CraftBukkit } - protected boolean canAddPassenger(Entity passenger) { -@@ -2611,7 +_,7 @@ + protected boolean canAddPassenger(final Entity passenger) { +@@ -2630,7 +_,7 @@ } public boolean isCrouching() { @@ -1268,7 +1276,7 @@ } public boolean isSprinting() { -@@ -2627,7 +_,7 @@ +@@ -2646,7 +_,7 @@ } public boolean isVisuallySwimming() { @@ -1277,10 +1285,10 @@ } public boolean isVisuallyCrawling() { -@@ -2635,6 +_,13 @@ +@@ -2654,6 +_,13 @@ } - public void setSwimming(boolean swimming) { + public void setSwimming(final boolean swimming) { + // CraftBukkit start + if (this.valid && this.isSwimming() != swimming && this instanceof net.minecraft.world.entity.LivingEntity) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callToggleSwimEvent((net.minecraft.world.entity.LivingEntity) this, swimming).isCancelled()) { @@ -1291,7 +1299,7 @@ this.setSharedFlag(FLAG_SWIMMING, swimming); } -@@ -2672,6 +_,7 @@ +@@ -2691,6 +_,7 @@ } public @Nullable PlayerTeam getTeam() { @@ -1299,10 +1307,10 @@ return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName()); } -@@ -2688,7 +_,11 @@ +@@ -2707,7 +_,11 @@ } - public void setInvisible(boolean invisible) { + public void setInvisible(final boolean invisible) { - this.setSharedFlag(FLAG_INVISIBLE, invisible); + // CraftBukkit - start + if (!this.persistentInvisibility) { // Prevent Minecraft from removing our invisibility flag @@ -1311,8 +1319,8 @@ + // CraftBukkit - end } - public boolean getSharedFlag(int flag) { -@@ -2705,7 +_,7 @@ + public boolean getSharedFlag(@Entity.Flags final int flag) { +@@ -2724,7 +_,7 @@ } public int getMaxAirSupply() { @@ -1321,19 +1329,21 @@ } public int getAirSupply() { -@@ -2713,10 +_,22 @@ +@@ -2732,10 +_,24 @@ } - public void setAirSupply(int airSupply) { -- this.entityData.set(DATA_AIR_SUPPLY_ID, airSupply); + public void setAirSupply(final int supply) { +- this.entityData.set(DATA_AIR_SUPPLY_ID, supply); + // CraftBukkit start -+ org.bukkit.event.entity.EntityAirChangeEvent event = new org.bukkit.event.entity.EntityAirChangeEvent(this.getBukkitEntity(), airSupply); ++ org.bukkit.event.entity.EntityAirChangeEvent event = new org.bukkit.event.entity.EntityAirChangeEvent(this.getBukkitEntity(), supply); + // Suppress during worldgen + if (this.valid) { + event.getEntity().getServer().getPluginManager().callEvent(event); + } -+ if (event.isCancelled() && this.getAirSupply() != airSupply) { -+ this.entityData.markDirty(DATA_AIR_SUPPLY_ID); ++ if (event.isCancelled() && this.getAirSupply() != supply) { ++ if (this instanceof ServerPlayer player) { ++ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_AIR_SUPPLY_ID), player); // todo is that even needed? ++ } + return; + } + this.entityData.set(DATA_AIR_SUPPLY_ID, event.getAmount()); @@ -1345,13 +1355,13 @@ this.setTicksFrozen(0); } -@@ -2743,11 +_,43 @@ +@@ -2762,11 +_,43 @@ - public void thunderHit(ServerLevel level, LightningBolt lightning) { + public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { this.setRemainingFireTicks(this.remainingFireTicks + 1); + // CraftBukkit start + final org.bukkit.entity.Entity thisBukkitEntity = this.getBukkitEntity(); -+ final org.bukkit.entity.Entity stormBukkitEntity = lightning.getBukkitEntity(); ++ final org.bukkit.entity.Entity stormBukkitEntity = lightningBolt.getBukkitEntity(); + final org.bukkit.plugin.PluginManager pluginManager = org.bukkit.Bukkit.getPluginManager(); + // CraftBukkit end if (this.remainingFireTicks == 0) { @@ -1386,14 +1396,14 @@ + return; + } + -+ if (!this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightning), 5.0F)) { // Paper - fix DamageSource API ++ if (!this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightningBolt), 5.0F)) { // Paper - fix DamageSource API + return; + } + // CraftBukkit end } - public void onAboveBubbleColumn(boolean downwards, BlockPos pos) { -@@ -2903,26 +_,30 @@ + public void onAboveBubbleColumn(final boolean dragDown, final BlockPos pos) { +@@ -2916,26 +_,30 @@ return this.removalReason != null ? String.format( Locale.ROOT, @@ -1403,7 +1413,7 @@ this.getPlainTextName(), this.id, + this.uuid, // Paper - add more info - string, + levelId, this.getX(), this.getY(), this.getZ(), @@ -1418,7 +1428,7 @@ this.getPlainTextName(), this.id, + this.uuid, // Paper - add more info - string, + levelId, this.getX(), this.getY(), - this.getZ() @@ -1427,35 +1437,37 @@ ); } -@@ -2946,6 +_,13 @@ +@@ -2959,6 +_,13 @@ } - public void restoreFrom(Entity entity) { + public void restoreFrom(final Entity oldEntity) { + // Paper start - Forward CraftEntity in teleport command -+ org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity = entity.bukkitEntity; ++ org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity = oldEntity.bukkitEntity; + if (bukkitEntity != null) { + bukkitEntity.setHandle(this); + this.bukkitEntity = bukkitEntity; + } + // Paper end - Forward CraftEntity in teleport command - try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { - TagValueOutput tagValueOutput = TagValueOutput.createWithContext(scopedCollector, entity.registryAccess()); - entity.saveWithoutId(tagValueOutput); -@@ -2957,7 +_,65 @@ + try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { + TagValueOutput entityData = TagValueOutput.createWithContext(reporter, oldEntity.registryAccess()); + oldEntity.saveWithoutId(entityData); +@@ -2969,8 +_,66 @@ + this.portalProcess = oldEntity.portalProcess; } - public @Nullable Entity teleport(TeleportTransition teleportTransition) { +- public @Nullable Entity teleport(final TeleportTransition transition) { ++ public @Nullable Entity teleport(TeleportTransition transition) { // Paper - remove param final + // Paper start - Fix item duplication and teleport issues -+ if ((!this.isAlive() || !this.valid) && (teleportTransition.newLevel() != this.level)) { -+ LOGGER.warn("Illegal Entity Teleport {} to {}:{}", this, teleportTransition.newLevel(), teleportTransition.position(), new Throwable()); ++ if ((!this.isAlive() || !this.valid) && (transition.newLevel() != this.level)) { ++ LOGGER.warn("Illegal Entity Teleport {} to {}:{}", this, transition.newLevel(), transition.position(), new Throwable()); + return null; + } + // Paper end - Fix item duplication and teleport issues if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved()) { + // CraftBukkit start -+ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); ++ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); + Vec3 velocity = absolutePosition.deltaMovement(); // Paper -+ org.bukkit.Location to = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), teleportTransition.newLevel(), absolutePosition.yRot(), absolutePosition.xRot()); ++ org.bukkit.Location to = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), transition.newLevel(), absolutePosition.yRot(), absolutePosition.xRot()); + // Paper start - gateway-specific teleport event + final org.bukkit.event.entity.EntityTeleportEvent teleEvent; + if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) Blocks.END_GATEWAY)) && this.level.getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { @@ -1470,7 +1482,7 @@ + } + if (!to.equals(teleEvent.getTo())) { + to = teleEvent.getTo(); -+ teleportTransition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), teleportTransition.missingRespawnBlock(), teleportTransition.asPassenger(), Set.of(), teleportTransition.postTeleportTransition(), teleportTransition.cause()); ++ transition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), transition.missingRespawnBlock(), transition.asPassenger(), Set.of(), transition.postTeleportTransition(), transition.cause()); + // Paper start - Call EntityPortalExitEvent + velocity = Vec3.ZERO; + } @@ -1496,7 +1508,7 @@ + to = event.getTo().clone(); + velocity = org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getAfter()); + } -+ teleportTransition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), velocity, to.getYaw(), to.getPitch(), teleportTransition.missingRespawnBlock(), teleportTransition.asPassenger(), Set.of(), teleportTransition.postTeleportTransition(), teleportTransition.cause()); ++ transition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), velocity, to.getYaw(), to.getPitch(), transition.missingRespawnBlock(), transition.asPassenger(), Set.of(), transition.postTeleportTransition(), transition.cause()); + } + } + if (this.isRemoved()) { @@ -1504,11 +1516,11 @@ + } + // Paper end - Call EntityPortalExitEvent + // CraftBukkit end - ServerLevel level = teleportTransition.newLevel(); - boolean flag = level.dimension() != serverLevel.dimension(); - if (!teleportTransition.asPassenger()) { -@@ -3006,10 +_,15 @@ - profilerFiller.pop(); + ServerLevel newLevel = transition.newLevel(); + boolean otherDimension = newLevel.dimension() != serverLevel.dimension(); + if (!transition.asPassenger()) { +@@ -3019,10 +_,15 @@ + profiler.pop(); return null; } else { + // Paper start - Fix item duplication and teleport issues @@ -1516,15 +1528,15 @@ + leashable.dropLeash(); // Paper drop lead + } + // Paper end - Fix item duplication and teleport issues - entityx.restoreFrom(this); + newEntity.restoreFrom(this); this.removeAfterChangingDimensions(); - entityx.teleportSetPosition(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); -- newLevel.addDuringTeleport(entityx); -+ if (this.inWorld) newLevel.addDuringTeleport(entityx); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned + newEntity.teleportSetPosition(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); +- newLevel.addDuringTeleport(newEntity); ++ if (this.inWorld) newLevel.addDuringTeleport(newEntity); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned - for (Entity entity2 : list) { - entity2.startRiding(entityx, true, false); -@@ -3099,9 +_,17 @@ + for (Entity newPassenger : newPassengers) { + newPassenger.startRiding(newEntity, true, false); +@@ -3109,9 +_,17 @@ } protected void removeAfterChangingDimensions() { @@ -1544,42 +1556,61 @@ + // Paper end - Expand EntityUnleashEvent } - if (this instanceof WaypointTransmitter waypointTransmitter && this.level instanceof ServerLevel serverLevel) { -@@ -3118,6 +_,7 @@ + if (this instanceof WaypointTransmitter waypoint && this.level instanceof ServerLevel serverLevel) { +@@ -3128,6 +_,7 @@ } - public boolean canTeleport(Level fromLevel, Level toLevel) { + public boolean canTeleport(final Level from, final Level to) { + if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues - if (fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD) { - for (Entity entity : this.getPassengers()) { - if (entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { -@@ -3224,13 +_,19 @@ - return this.entityData.get(DATA_CUSTOM_NAME_VISIBLE); + if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { + for (Entity passenger : this.getPassengers()) { + if (passenger instanceof ServerPlayer player && !player.seenCredits) { +@@ -3246,7 +_,7 @@ + } } -- public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera) { -- Entity entity = this.teleport(new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, yaw, pitch, relativeMovements, TeleportTransition.DO_NOTHING)); -+ // CraftBukkit start -+ public final boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera) { -+ return this.teleportTo(level, x, y, z, relativeMovements, yaw, pitch, setCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); +- public boolean teleportTo( ++ public final boolean teleportTo( // CraftBukkit - final + final ServerLevel level, + final double x, + final double y, +@@ -3256,14 +_,30 @@ + final float newXRot, + final boolean resetCamera + ) { ++ // CraftBukkit start ++ return this.teleportTo(level, x, y, z, relatives, newYRot, newXRot, resetCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + -+ public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { ++ public boolean teleportTo( ++ final ServerLevel level, ++ final double x, ++ final double y, ++ final double z, ++ final Set relatives, ++ final float newYRot, ++ final float newXRot, ++ final boolean resetCamera, ++ final org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause ++ ) { + // CraftBukkit end -+ Entity entity = this.teleport(new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, yaw, pitch, relativeMovements, TeleportTransition.DO_NOTHING, cause)); // CraftBukkit - return entity != null; + Entity newEntity = this.teleport( +- new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, newYRot, newXRot, relatives, TeleportTransition.DO_NOTHING) ++ new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, newYRot, newXRot, relatives, TeleportTransition.DO_NOTHING, cause) // CraftBukkit + ); + return newEntity != null; } - public void dismountTo(double x, double y, double z) { + public void dismountTo(final double x, final double y, final double z) { - this.teleportTo(x, y, z); + this.teleportTo(x, y, z); // Paper - diff on change for override } - public void teleportTo(double x, double y, double z) { -@@ -3339,7 +_,26 @@ + public void teleportTo(final double x, final double y, final double z) { +@@ -3374,7 +_,26 @@ } - public final void setBoundingBox(AABB bb) { + public final void setBoundingBox(final AABB bb) { - this.bb = bb; + // CraftBukkit start - block invalid bounding boxes + double minX = bb.minX, @@ -1603,11 +1634,11 @@ + // CraftBukkit end } - public final float getEyeHeight(Pose pose) { -@@ -3367,6 +_,12 @@ + public final float getEyeHeight(final Pose pose) { +@@ -3398,6 +_,12 @@ } - public void stopSeenByPlayer(ServerPlayer player) { + public void stopSeenByPlayer(final ServerPlayer player) { + // Paper start - entity tracking events + // Since this event cannot be cancelled, we should call it here to catch all "un-tracks" + if (io.papermc.paper.event.player.PlayerUntrackEntityEvent.getHandlerList().getRegisteredListeners().length > 0) { @@ -1616,8 +1647,8 @@ + // Paper end - entity tracking events } - public float rotate(Rotation transformRotation) { -@@ -3425,21 +_,32 @@ + public float rotate(final Rotation rotation) { +@@ -3456,21 +_,32 @@ } private Stream getIndirectPassengersStream() { @@ -1651,7 +1682,7 @@ } public int countPlayerPassengers() { -@@ -3447,6 +_,7 @@ +@@ -3478,6 +_,7 @@ } public boolean hasExactlyOnePlayerPassenger() { @@ -1659,7 +1690,7 @@ return this.countPlayerPassengers() == 1; } -@@ -3527,9 +_,38 @@ +@@ -3558,9 +_,38 @@ return 0; } @@ -1692,28 +1723,16 @@ + }; + // CraftBukkit end + - public CommandSourceStack createCommandSourceStackForNameResolution(ServerLevel level) { + public CommandSourceStack createCommandSourceStackForNameResolution(final ServerLevel level) { return new CommandSourceStack( - CommandSource.NULL, + this.commandSource, // CraftBukkit this.position(), this.getRotationVector(), level, -@@ -3595,6 +_,11 @@ - vec3 = vec3.add(flow); - i++; - } -+ // CraftBukkit start - store last lava contact location -+ if (fluidTag == FluidTags.LAVA) { -+ this.lastLavaContact = mutableBlockPos.immutable(); -+ } -+ // CraftBukkit end - } - } - } -@@ -3694,7 +_,9 @@ +@@ -3658,7 +_,9 @@ - public void setDeltaMovement(Vec3 deltaMovement) { + public void setDeltaMovement(final Vec3 deltaMovement) { if (deltaMovement.isFinite()) { + synchronized (this.posLock) { // Paper - detailed watchdog information this.deltaMovement = deltaMovement; @@ -1721,11 +1740,14 @@ } } -@@ -3760,9 +_,35 @@ - return this.getZ((2.0 * this.random.nextDouble() - 1.0) * scale); +@@ -3729,8 +_,34 @@ } -+ // Paper start - Block invalid positions and bounding box + public final void setPosRaw(final double x, final double y, final double z) { ++ // Paper start - Block invalid positions and bounding box ++ this.setPosRaw(x, y, z, false); ++ } ++ + public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) { + if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) { + return true; @@ -1740,10 +1762,6 @@ + LOGGER.error("New entity position is invalid! Tried to set invalid position ({},{},{}) for entity {} located at {}, entity info: {}", newX, newY, newZ, entity.getClass().getName(), entity.position(), entityInfo, new Throwable()); + return false; + } -+ - public final void setPosRaw(double x, double y, double z) { -+ this.setPosRaw(x, y, z, false); -+ } + + public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { + if (!checkPosition(this, x, y, z)) { @@ -1754,11 +1772,11 @@ + synchronized (this.posLock) { // Paper - detailed watchdog information this.position = new Vec3(x, y, z); + } // Paper - detailed watchdog information - int floor = Mth.floor(x); - int floor1 = Mth.floor(y); - int floor2 = Mth.floor(z); -@@ -3784,7 +_,18 @@ - serverLevel.getWaypointManager().updatePlayer(serverPlayer); + int fx = Mth.floor(x); + int fy = Mth.floor(y); + int fz = Mth.floor(z); +@@ -3752,7 +_,18 @@ + serverLevel.getWaypointManager().updatePlayer(player); } } - } @@ -1777,7 +1795,7 @@ } public void checkDespawn() { -@@ -3836,6 +_,12 @@ +@@ -3804,6 +_,12 @@ return this.getTicksFrozen() > 0; } @@ -1790,23 +1808,23 @@ public float getYRot() { return this.yRot; } -@@ -3886,7 +_,9 @@ +@@ -3854,7 +_,9 @@ } @Override -- public final void setRemoved(Entity.RemovalReason removalReason) { -+ public final void setRemoved(Entity.RemovalReason removalReason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause +- public final void setRemoved(final Entity.RemovalReason reason) { ++ public final void setRemoved(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause + org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit + final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { - this.removalReason = removalReason; + this.removalReason = reason; } -@@ -3898,12 +_,28 @@ +@@ -3866,12 +_,28 @@ this.getPassengers().forEach(Entity::stopRiding); - this.levelCallback.onRemove(removalReason); - this.onRemoval(removalReason); + this.levelCallback.onRemove(reason); + this.onRemoval(reason); + // Paper start - Folia schedulers -+ if (!(this instanceof ServerPlayer) && removalReason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { ++ if (!(this instanceof ServerPlayer) && reason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { + // Players need to be special cased, because they are regularly removed from the world + this.retireScheduler(); + } @@ -1828,9 +1846,9 @@ + // Paper end - Folia schedulers + @Override - public void setLevelCallback(EntityInLevelCallback levelCallback) { + public void setLevelCallback(final EntityInLevelCallback levelCallback) { this.levelCallback = levelCallback; -@@ -4101,4 +_,14 @@ +@@ -4093,4 +_,14 @@ return this.save; } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityEquipment.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityEquipment.java.patch index 391fd01b5702..4893f35cf282 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityEquipment.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityEquipment.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/entity/EntityEquipment.java @@ -70,4 +_,11 @@ public void clear() { - this.items.replaceAll((equipmentSlot, itemStack) -> ItemStack.EMPTY); + this.items.replaceAll((s, v) -> ItemStack.EMPTY); } + + // Paper start - EntityDeathEvent diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityFluidInteraction.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityFluidInteraction.java.patch new file mode 100644 index 000000000000..2a6661d49289 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityFluidInteraction.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/entity/EntityFluidInteraction.java ++++ b/net/minecraft/world/entity/EntityFluidInteraction.java +@@ -77,6 +_,11 @@ + } + + tracker.accumulateCurrent(flow); ++ // CraftBukkit start - store last lava contact location ++ if (fluidState.is(net.minecraft.tags.FluidTags.LAVA)) { ++ entity.lastLavaContact = mutablePos.immutable(); ++ } ++ // CraftBukkit end - store last lava contact location + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityReference.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityReference.java.patch index 0a2cd6195a45..58febb531c20 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityReference.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityReference.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/EntityReference.java +++ b/net/minecraft/world/entity/EntityReference.java -@@ -140,4 +_,15 @@ +@@ -142,4 +_,15 @@ public int hashCode() { return this.getUUID().hashCode(); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch index c4e53b4c8a31..7cd390264779 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch @@ -3,7 +3,7 @@ @@ -17,6 +_,22 @@ public static final Predicate NO_SPECTATORS = entity -> !entity.isSpectator(); public static final Predicate CAN_BE_COLLIDED_WITH = NO_SPECTATORS.and(entity -> entity.canBeCollidedWith(null)); - public static final Predicate CAN_BE_PICKED = NO_SPECTATORS.and(Entity::isPickable); + public static final Predicate CAN_BE_PICKED = Entity::isPickable; + // Paper start - Ability to control player's insomnia and phantoms + public static Predicate IS_INSOMNIAC = (player) -> { + int playerInsomniaTicks = player.level().paperConfig().entities.behavior.playerInsomniaStartTicks; @@ -23,20 +23,18 @@ private EntitySelector() { } -@@ -32,13 +_,13 @@ - return (Predicate)(collisionRule == Team.CollisionRule.NEVER +@@ -33,12 +_,12 @@ ? Predicates.alwaysFalse() : NO_SPECTATORS.and( -- entity1 -> { -- if (!entity1.isPushable()) { -+ entity1 -> { final Entity pushedEntity = entity1; // Paper - OBFHELPER -+ if (!pushedEntity.isPushable() || !pushedEntity.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(pushedEntity)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule + input -> { +- if (!input.isPushable()) { ++ if (!input.isPushable() || !input.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(input)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule return false; - } else if (!entity.level().isClientSide() || entity1 instanceof Player player && player.isLocalPlayer()) { - Team team1 = entity1.getTeam(); - Team.CollisionRule collisionRule1 = team1 == null ? Team.CollisionRule.ALWAYS : team1.getCollisionRule(); -- if (collisionRule1 == Team.CollisionRule.NEVER) { -+ if (collisionRule1 == Team.CollisionRule.NEVER || (pushedEntity instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions)) { // Paper - Configurable player collision + } else if (!entity.level().isClientSide() || input instanceof Player player && player.isLocalPlayer()) { + Team theirTeam = input.getTeam(); + Team.CollisionRule theirCollisionRule = theirTeam == null ? Team.CollisionRule.ALWAYS : theirTeam.getCollisionRule(); +- if (theirCollisionRule == Team.CollisionRule.NEVER) { ++ if (theirCollisionRule == Team.CollisionRule.NEVER || (input instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions)) { // Paper - Configurable player collision return false; } else { - boolean flag = team != null && team.isAlliedTo(team1); + boolean sameTeam = ownTeam != null && ownTeam.isAlliedTo(theirTeam); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch index 54535b61d022..849af41b4e84 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch @@ -1,84 +1,100 @@ --- a/net/minecraft/world/entity/EntityType.java +++ b/net/minecraft/world/entity/EntityType.java -@@ -189,6 +_,7 @@ +@@ -187,6 +_,7 @@ import org.slf4j.Logger; - public class EntityType implements FeatureElement, EntityTypeTest { + public class EntityType implements EntityTypeTest, FeatureElement { + private static final boolean DEBUG_ENTITIES_WITH_INVALID_IDS = Boolean.getBoolean("paper.debugEntitiesWithInvalidIds"); // Paper - Add logging for debugging entity tags with invalid ids private static final Logger LOGGER = LogUtils.getLogger(); private final Holder.Reference> builtInRegistryHolder = BuiltInRegistries.ENTITY_TYPE.createIntrusiveHolder(this); public static final Codec> CODEC = BuiltInRegistries.ENTITY_TYPE.byNameCodec(); -@@ -1290,6 +_,22 @@ - boolean shouldOffsetY, - boolean shouldOffsetYMore +@@ -1288,6 +_,22 @@ + final boolean tryMoveDown, + final boolean movedUp ) { + // CraftBukkit start -+ return this.spawn(level, spawnedFrom, owner, pos, spawnReason, shouldOffsetY, shouldOffsetYMore, spawnReason == EntitySpawnReason.DISPENSER ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // Paper - use correct spawn reason for dispenser spawn eggs ++ return this.spawn(level, itemStack, user, spawnPos, spawnReason, tryMoveDown, movedUp, spawnReason == EntitySpawnReason.DISPENSER ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // Paper - use correct spawn reason for dispenser spawn eggs + } + + @Nullable + public T spawn( -+ ServerLevel level, -+ @Nullable ItemStack spawnedFrom, -+ @Nullable LivingEntity owner, -+ BlockPos pos, -+ EntitySpawnReason spawnReason, -+ boolean shouldOffsetY, -+ boolean shouldOffsetYMore, -+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason createSpawnReason ++ final ServerLevel level, ++ final @Nullable ItemStack itemStack, ++ final @Nullable LivingEntity user, ++ final BlockPos spawnPos, ++ final EntitySpawnReason spawnReason, ++ final boolean tryMoveDown, ++ final boolean movedUp, ++ final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason createSpawnReason + ) { + // CraftBukkit end - Consumer consumer; - if (spawnedFrom != null) { - consumer = createDefaultStackConfig(level, spawnedFrom, owner); -@@ -1297,7 +_,7 @@ - consumer = entity -> {}; + Consumer postSpawnConfig; + if (itemStack != null) { + postSpawnConfig = createDefaultStackConfig(level, itemStack, user); +@@ -1295,7 +_,7 @@ + postSpawnConfig = entity -> {}; } -- return this.spawn(level, consumer, pos, spawnReason, shouldOffsetY, shouldOffsetYMore); -+ return this.spawn(level, consumer, pos, spawnReason, shouldOffsetY, shouldOffsetYMore, createSpawnReason); // CraftBukkit +- return this.spawn(level, postSpawnConfig, spawnPos, spawnReason, tryMoveDown, movedUp); ++ return this.spawn(level, postSpawnConfig, spawnPos, spawnReason, tryMoveDown, movedUp, createSpawnReason); // CraftBukkit } - public static Consumer createDefaultStackConfig(Level level, ItemStack stack, @Nullable LivingEntity owner) { -@@ -1314,19 +_,54 @@ - - public static Consumer appendCustomEntityStackConfig(Consumer consumer, Level level, ItemStack stack, @Nullable LivingEntity owner) { - TypedEntityData> typedEntityData = stack.get(DataComponents.ENTITY_DATA); -- return typedEntityData != null ? consumer.andThen(entity -> updateCustomEntityTag(level, owner, entity, typedEntityData)) : consumer; + public static Consumer createDefaultStackConfig(final Level level, final ItemStack itemStack, final @Nullable LivingEntity user) { +@@ -1316,11 +_,30 @@ + final Consumer initialConfig, final Level level, final ItemStack itemStack, final @Nullable LivingEntity user + ) { + TypedEntityData> entityData = itemStack.get(DataComponents.ENTITY_DATA); +- return entityData != null ? initialConfig.andThen(entity -> updateCustomEntityTag(level, user, entity, entityData)) : initialConfig; + // CraftBukkit start - SPIGOT-5665 -+ return typedEntityData != null ? consumer.andThen(entity -> { ++ return entityData != null ? initialConfig.andThen(entity -> { + try { -+ updateCustomEntityTag(level, owner, entity, typedEntityData); ++ updateCustomEntityTag(level, user, entity, entityData); + } catch (Throwable t) { + LOGGER.warn("Error loading spawn egg NBT", t); + } -+ }) : consumer; ++ }) : initialConfig; + // CraftBukkit end } - public @Nullable T spawn(ServerLevel level, BlockPos pos, EntitySpawnReason spawnReason) { -- return this.spawn(level, null, pos, spawnReason, false, false); + public @Nullable T spawn(final ServerLevel level, final BlockPos spawnPos, final EntitySpawnReason spawnReason) { +- return this.spawn(level, null, spawnPos, spawnReason, false, false); + // CraftBukkit start -+ return this.spawn(level, pos, spawnReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ return this.spawn(level, spawnPos, spawnReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } -+ public @Nullable T spawn(ServerLevel level, BlockPos pos, EntitySpawnReason spawnReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason) { -+ return this.spawn(level, null, pos, spawnReason, false, false, creatureSpawnReason); ++ ++ public @Nullable T spawn( ++ final ServerLevel level, ++ final BlockPos spawnPos, ++ final EntitySpawnReason spawnReason, ++ final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason ++ ) { ++ return this.spawn(level, null, spawnPos, spawnReason, false, false, creatureSpawnReason); + // CraftBukkit End } public @Nullable T spawn( - ServerLevel level, @Nullable Consumer consumer, BlockPos pos, EntitySpawnReason spawnReason, boolean shouldOffsetY, boolean shouldOffsetYMore +@@ -1331,9 +_,39 @@ + final boolean tryMoveDown, + final boolean movedUp ) { + // CraftBukkit start -+ return this.spawn(level, consumer, pos, spawnReason, shouldOffsetY, shouldOffsetYMore, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ return this.spawn(level, postSpawnConfig, spawnPos, spawnReason, tryMoveDown, movedUp, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + @Nullable -+ public T spawn(ServerLevel level, @Nullable Consumer consumer, BlockPos pos, EntitySpawnReason spawnReason, boolean shouldOffsetY, boolean shouldOffsetYMore, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason) { ++ public T spawn( ++ final ServerLevel level, ++ final @Nullable Consumer postSpawnConfig, ++ final BlockPos spawnPos, ++ final EntitySpawnReason spawnReason, ++ final boolean tryMoveDown, ++ final boolean movedUp, ++ final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason ++ ) { + // CraftBukkit end + // Paper start - PreCreatureSpawnEvent + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, level), + org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(this), + creatureSpawnReason + ); @@ -86,7 +102,7 @@ + return null; + } + // Paper end - PreCreatureSpawnEvent - T entity = this.create(level, consumer, pos, spawnReason, shouldOffsetY, shouldOffsetYMore); + T entity = this.create(level, postSpawnConfig, spawnPos, spawnReason, tryMoveDown, movedUp); if (entity != null) { - level.addFreshEntityWithPassengers(entity); + // CraftBukkit start @@ -98,12 +114,12 @@ if (entity instanceof Mob mob) { mob.playAmbientSound(); } -@@ -1382,6 +_,13 @@ +@@ -1396,6 +_,13 @@ if (level.isClientSide() || !entity.getType().onlyOpCanSetNbt() - || owner instanceof Player player && server.getPlayerList().isOp(player.nameAndId())) { + || user instanceof Player player && server.getPlayerList().isOp(player.nameAndId())) { + // Paper start - filter out protected tags -+ if (owner == null || !owner.getBukkitEntity().hasPermission("minecraft.nbt.place")) { ++ if (user == null || !user.getBukkitEntity().hasPermission("minecraft.nbt.place")) { + for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : level.paperConfig().entities.spawning.filteredEntityTagNbtPaths) { + tag.remove(entityData.getUnsafe()); + } @@ -112,18 +128,18 @@ entityData.loadInto(entity); } } -@@ -1452,10 +_,28 @@ +@@ -1466,10 +_,28 @@ } - public static Optional create(ValueInput input, Level level, EntitySpawnReason spawnReason) { + public static Optional create(final ValueInput input, final Level level, final EntitySpawnReason reason) { + // Paper start - Don't fire sync event during generation -+ return create(input, level, spawnReason, false); ++ return create(input, level, reason, false); + } + -+ public static Optional create(ValueInput input, Level level, EntitySpawnReason spawnReason, boolean generation) { ++ public static Optional create(final ValueInput input, final Level level, final EntitySpawnReason reason, final boolean generation) { + // Paper end - Don't fire sync event during generation return Util.ifElse( - by(input).map(entityType -> entityType.create(level, spawnReason)), + by(input).map(type -> type.create(level, reason)), - entity -> entity.load(input), - () -> LOGGER.warn("Skipping Entity with id {}", input.getStringOr("id", "[invalid]")) + // Paper start - Don't fire sync event during generation @@ -143,7 +159,7 @@ ); } -@@ -1606,8 +_,23 @@ +@@ -1616,8 +_,23 @@ return this.builtInRegistryHolder; } @@ -167,4 +183,4 @@ + // Paper end } - private static EntityType.EntityFactory boatFactory(Supplier boatItemGetter) { + private static EntityType.EntityFactory boatFactory(final Supplier boatItem) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch index 77020cd48c6a..c63e98f57f82 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch @@ -33,22 +33,22 @@ + } + // Paper end + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - overload ctor - public ExperienceOrb(Level level, double x, double y, double z, int value) { + public ExperienceOrb(final Level level, final double x, final double y, final double z, final int value) { - this(level, new Vec3(x, y, z), Vec3.ZERO, value); + // Paper start - add reasons for orbs + this(level, x, y, z, value, null, null, null); + } -+ public ExperienceOrb(Level level, double x, double y, double z, int value, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, @Nullable Entity triggerId, @Nullable Entity sourceId) { ++ public ExperienceOrb(final Level level, final double x, final double y, final double z, final int value, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, final @Nullable Entity triggerId, final @Nullable Entity sourceId) { + this(level, new Vec3(x, y, z), Vec3.ZERO, value, reason, triggerId, sourceId); + // Paper end - add reasons for orbs } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - overload ctor - public ExperienceOrb(Level level, Vec3 pos, Vec3 direction, int value) { + public ExperienceOrb(final Level level, final Vec3 pos, final Vec3 roughly, final int value) { + // Paper start - add reasons for orbs -+ this(level, pos, direction, value, null, null, null); ++ this(level, pos, roughly, value, null, null, null); + } -+ public ExperienceOrb(Level level, Vec3 pos, Vec3 direction, int value, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, @Nullable Entity triggerId, @Nullable Entity sourceId) { ++ public ExperienceOrb(final Level level, final Vec3 pos, final Vec3 roughly, final int value, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, final @Nullable Entity triggerId, final @Nullable Entity sourceId) { + // Paper end - add reasons for orbs this(EntityType.EXPERIENCE_ORB, level); + // Paper start - add reasons for orbs @@ -97,45 +97,45 @@ + + if (this.followingPlayer != null && !cancelled) { + // CraftBukkit end - Vec3 vec3 = new Vec3( + Vec3 delta = new Vec3( this.followingPlayer.getX() - this.getX(), this.followingPlayer.getY() + this.followingPlayer.getEyeHeight() / 2.0 - this.getY(), -@@ -192,18 +_,24 @@ +@@ -191,18 +_,24 @@ } - public static void awardWithDirection(ServerLevel level, Vec3 pos, Vec3 direction, int amount) { + public static void awardWithDirection(final ServerLevel level, final Vec3 pos, final Vec3 roughDirection, int amount) { + // Paper start - add reason to orbs -+ awardWithDirection(level, pos, direction, amount, null, null, null); ++ awardWithDirection(level, pos, roughDirection, amount, null, null, null); + } -+ public static void awardWithDirection(ServerLevel level, Vec3 pos, Vec3 direction, int amount, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, @Nullable Entity triggerId, @Nullable Entity sourceId) { ++ public static void awardWithDirection(final ServerLevel level, final Vec3 pos, final Vec3 roughDirection, int amount, org.bukkit.entity.ExperienceOrb.@Nullable SpawnReason reason, final @Nullable Entity triggerId, final @Nullable Entity sourceId) { + // Paper end - add reason to orbs while (amount > 0) { - int experienceValue = getExperienceValue(amount); - amount -= experienceValue; - if (!tryMergeToExisting(level, pos, experienceValue)) { -- level.addFreshEntity(new ExperienceOrb(level, pos, direction, experienceValue)); -+ level.addFreshEntity(new ExperienceOrb(level, pos, direction, experienceValue, reason, triggerId, sourceId)); // Paper - add reason to orbs + int newCount = getExperienceValue(amount); + amount -= newCount; + if (!tryMergeToExisting(level, pos, newCount)) { +- level.addFreshEntity(new ExperienceOrb(level, pos, roughDirection, newCount)); ++ level.addFreshEntity(new ExperienceOrb(level, pos, roughDirection, newCount, reason, triggerId, sourceId)); // Paper - add reason to orbs } } } - private static boolean tryMergeToExisting(ServerLevel level, Vec3 pos, int amount) { + private static boolean tryMergeToExisting(final ServerLevel level, final Vec3 pos, final int value) { + // Paper - TODO some other event for this kind of merge - AABB aabb = AABB.ofSize(pos, 1.0, 1.0, 1.0); -- int randomInt = level.getRandom().nextInt(40); -+ int randomInt = level.getRandom().nextInt(io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA)); // Paper - Configure how many orb groups per area - List entities = level.getEntities( - EntityTypeTest.forClass(ExperienceOrb.class), aabb, experienceOrb1 -> canMerge(experienceOrb1, randomInt, amount) - ); -@@ -222,13 +_,18 @@ + AABB box = AABB.ofSize(pos, 1.0, 1.0, 1.0); +- int id = level.getRandom().nextInt(40); ++ int id = level.getRandom().nextInt(io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA)); // Paper - Configure how many orb groups per area + List orbs = level.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), box, orbx -> canMerge(orbx, id, value)); + if (!orbs.isEmpty()) { + ExperienceOrb orb = orbs.get(0); +@@ -219,13 +_,18 @@ } - private static boolean canMerge(ExperienceOrb orb, int amount, int other) { -- return !orb.isRemoved() && (orb.getId() - amount) % 40 == 0 && orb.getValue() == other; -+ return !orb.isRemoved() && (orb.getId() - amount) % io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA) == 0 && orb.getValue() == other; // Paper - Configure how many orbs will merge together + private static boolean canMerge(final ExperienceOrb orb, final int id, final int value) { +- return !orb.isRemoved() && (orb.getId() - id) % 40 == 0 && orb.getValue() == value; ++ return !orb.isRemoved() && (orb.getId() - id) % io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA) == 0 && orb.getValue() == value; // Paper - Configure how many orbs will merge together } - private void merge(ExperienceOrb orb) { + private void merge(final ExperienceOrb orb) { + // Paper start - call orb merge event + if (!new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) this.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) orb.getBukkitEntity()).callEvent()) { + return; @@ -148,17 +148,17 @@ } private void setUnderwaterMovement() { -@@ -253,7 +_,7 @@ +@@ -250,7 +_,7 @@ this.markHurt(); - this.health = (int)(this.health - amount); + this.health = (int)(this.health - damage); if (this.health <= 0) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause } return true; -@@ -264,32 +_,34 @@ - protected void addAdditionalSaveData(ValueOutput output) { +@@ -261,32 +_,34 @@ + protected void addAdditionalSaveData(final ValueOutput output) { output.putShort("Health", (short)this.health); output.putShort("Age", (short)this.age); - output.putShort("Value", (short)this.getValue()); @@ -168,7 +168,7 @@ } @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { this.health = input.getShortOr("Health", (short)5); this.age = input.getShortOr("Age", (short)0); - this.setValue(input.getShortOr("Value", (short)0)); @@ -178,17 +178,17 @@ } @Override - public void playerTouch(Player entity) { - if (entity instanceof ServerPlayer serverPlayer) { -- if (entity.takeXpDelay == 0) { -- entity.takeXpDelay = 2; -+ if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent -+ entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2; - entity.take(this, 1); - int i = this.repairPlayerItems(serverPlayer, this.getValue()); - if (i > 0) { -- entity.giveExperiencePoints(i); -+ entity.giveExperiencePoints(org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerExpChangeEvent(entity, this, i).getAmount()); // CraftBukkit - i -> event.getAmount() // Paper - supply experience orb + public void playerTouch(final Player player) { + if (player instanceof ServerPlayer serverPlayer) { +- if (player.takeXpDelay == 0) { +- player.takeXpDelay = 2; ++ if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent ++ player.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(player, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2; + player.take(this, 1); + int remaining = this.repairPlayerItems(serverPlayer, this.getValue()); + if (remaining > 0) { +- player.giveExperiencePoints(remaining); ++ player.giveExperiencePoints(org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerExpChangeEvent(player, this, remaining).getAmount()); // CraftBukkit - remaining -> event.getAmount() // Paper - supply experience orb } this.count--; @@ -198,49 +198,49 @@ } } } -@@ -303,9 +_,19 @@ - ItemStack itemStack = randomItemWith.get().itemStack(); - int i = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), itemStack, value); - int min = Math.min(i, itemStack.getDamageValue()); +@@ -298,9 +_,19 @@ + ItemStack itemStack = selected.get().itemStack(); + int toRepairFromXpAmount = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), itemStack, amount); + int repair = Math.min(toRepairFromXpAmount, itemStack.getDamageValue()); + // CraftBukkit start + // Paper start - mending event -+ final int consumedExperience = min > 0 ? min * value / i : 0; -+ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(player, this, itemStack, randomItemWith.get().inSlot(), min, consumedExperience); ++ final int consumedExperience = repair > 0 ? repair * amount / toRepairFromXpAmount : 0; ++ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(player, this, itemStack, selected.get().inSlot(), repair, consumedExperience); + // Paper end - mending event -+ min = event.getRepairAmount(); ++ repair = event.getRepairAmount(); + if (event.isCancelled()) { -+ return value; ++ return amount; + } + // CraftBukkit end - itemStack.setDamageValue(itemStack.getDamageValue() - min); - if (min > 0) { -- int i1 = value - min * value / i; -+ int i1 = value - min * value / i; // Paper - diff on change - expand PlayerMendEvents - if (i1 > 0) { - return this.repairPlayerItems(player, i1); + itemStack.setDamageValue(itemStack.getDamageValue() - repair); + if (repair > 0) { +- int remaining = amount - repair * amount / toRepairFromXpAmount; ++ int remaining = amount - repair * amount / toRepairFromXpAmount; // Paper - diff on change - expand PlayerMendEvents + if (remaining > 0) { + return this.repairPlayerItems(player, remaining); } -@@ -351,6 +_,24 @@ +@@ -346,6 +_,24 @@ } - public static int getExperienceValue(int expValue) { + public static int getExperienceValue(final int maxValue) { + // CraftBukkit start -+ if (expValue > 162670129) return expValue - 100000; -+ if (expValue > 81335063) return 81335063; -+ if (expValue > 40667527) return 40667527; -+ if (expValue > 20333759) return 20333759; -+ if (expValue > 10166857) return 10166857; -+ if (expValue > 5083423) return 5083423; -+ if (expValue > 2541701) return 2541701; -+ if (expValue > 1270849) return 1270849; -+ if (expValue > 635413) return 635413; -+ if (expValue > 317701) return 317701; -+ if (expValue > 158849) return 158849; -+ if (expValue > 79423) return 79423; -+ if (expValue > 39709) return 39709; -+ if (expValue > 19853) return 19853; -+ if (expValue > 9923) return 9923; -+ if (expValue > 4957) return 4957; ++ if (maxValue > 162670129) return maxValue - 100000; ++ if (maxValue > 81335063) return 81335063; ++ if (maxValue > 40667527) return 40667527; ++ if (maxValue > 20333759) return 20333759; ++ if (maxValue > 10166857) return 10166857; ++ if (maxValue > 5083423) return 5083423; ++ if (maxValue > 2541701) return 2541701; ++ if (maxValue > 1270849) return 1270849; ++ if (maxValue > 635413) return 635413; ++ if (maxValue > 317701) return 317701; ++ if (maxValue > 158849) return 158849; ++ if (maxValue > 79423) return 79423; ++ if (maxValue > 39709) return 39709; ++ if (maxValue > 19853) return 19853; ++ if (maxValue > 9923) return 9923; ++ if (maxValue > 4957) return 4957; + // CraftBukkit end - if (expValue >= 2477) { + if (maxValue >= 2477) { return 2477; - } else if (expValue >= 1237) { + } else if (maxValue >= 1237) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch index 27a6b68777b2..d459738f55c7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch @@ -7,40 +7,40 @@ - private final Set effectsInStep = EnumSet.noneOf(InsideBlockEffectType.class); + private final Map> effectsInStep = new java.util.EnumMap<>(InsideBlockEffectType.class); // Paper - track position inside effect was triggered on private final Map>> beforeEffectsInStep = Util.makeEnumMap( - InsideBlockEffectType.class, insideBlockEffectType -> new ArrayList<>() + InsideBlockEffectType.class, type -> new ArrayList<>() ); @@ -42,7 +_,8 @@ private final List> finalEffects = new ArrayList<>(); private int lastStep = -1; -- public void advanceStep(int step) { -+ public void advanceStep(int step, net.minecraft.core.BlockPos pos) { // Paper - track position inside effect was triggered on +- public void advanceStep(final int step) { ++ public void advanceStep(final int step, net.minecraft.core.BlockPos pos) { // Paper - track position inside effect was triggered on + this.currentBlockPos = pos; // Paper - track position inside effect was triggered on if (this.lastStep != step) { this.lastStep = step; this.flushStep(); @@ -69,8 +_,8 @@ - List> list = this.beforeEffectsInStep.get(insideBlockEffectType); - this.finalEffects.addAll(list); - list.clear(); -- if (this.effectsInStep.remove(insideBlockEffectType)) { -- this.finalEffects.add(insideBlockEffectType.effect()); -+ if (this.effectsInStep.remove(insideBlockEffectType) instanceof final Consumer recordedEffect) { // Paper - track position inside effect was triggered on - better than null check to avoid diff. + List> beforeEffects = this.beforeEffectsInStep.get(type); + this.finalEffects.addAll(beforeEffects); + beforeEffects.clear(); +- if (this.effectsInStep.remove(type)) { +- this.finalEffects.add(type.effect()); ++ if (this.effectsInStep.remove(type) instanceof final Consumer recordedEffect) { // Paper - track position inside effect was triggered on - better than null check to avoid diff. + this.finalEffects.add(recordedEffect); // Paper - track position inside effect was triggered on } - List> list1 = this.afterEffectsInStep.get(insideBlockEffectType); + List> afterEffects = this.afterEffectsInStep.get(type); @@ -81,7 +_,7 @@ @Override - public void apply(InsideBlockEffectType type) { + public void apply(final InsideBlockEffectType type) { - this.effectsInStep.add(type); -+ this.effectsInStep.put(type, recorded(type)); // Paper - track position inside effect was triggered on ++ this.effectsInStep.put(type, recorded(type)); // Paper - track position inside effect was triggered on } @Override @@ -93,5 +_,24 @@ - public void runAfter(InsideBlockEffectType type, Consumer effect) { + public void runAfter(final InsideBlockEffectType type, final Consumer effect) { this.afterEffectsInStep.get(type).add(effect); } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Interaction.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Interaction.java.patch index 64ff18b39efb..836e158702a1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Interaction.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Interaction.java.patch @@ -2,11 +2,11 @@ +++ b/net/minecraft/world/entity/Interaction.java @@ -99,9 +_,16 @@ @Override - public boolean skipAttackInteraction(Entity entity) { - if (entity instanceof Player player) { + public boolean skipAttackInteraction(final Entity source) { + if (source instanceof Player player) { + // CraftBukkit start -+ DamageSource source = player.damageSources().generic().eventEntityDamager(entity); -+ org.bukkit.event.entity.EntityDamageEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNonLivingEntityDamageEvent(this, source, 1.0F, false); ++ DamageSource damageSource = player.damageSources().generic().eventEntityDamager(source); ++ org.bukkit.event.entity.EntityDamageEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNonLivingEntityDamageEvent(this, damageSource, 1.0F, false); + if (event.isCancelled()) { + return true; + } @@ -14,7 +14,7 @@ this.attack = new Interaction.PlayerAction(player.getUUID(), this.level().getGameTime()); if (player instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, player.damageSources().generic(), 1.0F, 1.0F, false); -+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, source, 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit ++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(serverPlayer, this, damageSource, 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit } return !this.getResponse(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch index 568f7284c189..07394f09b1c6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Leashable.java.patch @@ -3,7 +3,7 @@ @@ -79,6 +_,11 @@ } - default void writeLeashData(ValueOutput output, Leashable.@Nullable LeashData leashData) { + default void writeLeashData(final ValueOutput output, final Leashable.@Nullable LeashData leashData) { + // CraftBukkit start - SPIGOT-7487: Don't save (and possible drop) leash, when the holder was removed by a plugin + if (leashData != null && leashData.leashHolder != null && leashData.leashHolder.pluginRemoved) { + return; @@ -24,14 +24,14 @@ } @@ -122,7 +_,9 @@ entity.onLeashRemoved(); - if (entity.level() instanceof ServerLevel serverLevel) { - if (dropItem) { + if (entity.level() instanceof ServerLevel level) { + if (dropLead) { + entity.forceDrops = true; // CraftBukkit - entity.spawnAtLocation(serverLevel, Items.LEAD); + entity.spawnAtLocation(level, Items.LEAD); + entity.forceDrops = false; // CraftBukkit } - if (broadcastPacket) { + if (sendPacket) { @@ -142,7 +_,15 @@ if (leashData != null && leashData.leashHolder != null) { @@ -51,13 +51,13 @@ entity.removeLeash(); @@ -153,8 +_,7 @@ if (leashHolder != null && leashHolder.level() == entity.level()) { - double d = entity.leashDistanceTo(leashHolder); + double distanceTo = entity.leashDistanceTo(leashHolder); entity.whenLeashedTo(leashHolder); -- if (d > entity.leashSnapDistance()) { +- if (distanceTo > entity.leashSnapDistance()) { - level.playSound(null, leashHolder.getX(), leashHolder.getY(), leashHolder.getZ(), SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F); -+ if (d > entity.leashSnapDistanceOrConfig()) { // Paper - Configurable max leash distance ++ if (distanceTo > entity.leashSnapDistanceOrConfig()) { // Paper - Configurable max leash distance entity.leashTooFarBehaviour(); - } else if (d > entity.leashElasticDistance() - leashHolder.getBbWidth() - entity.getBbWidth() + } else if (distanceTo > entity.leashElasticDistance() - leashHolder.getBbWidth() - entity.getBbWidth() && entity.checkElasticInteractions(leashHolder, leashData)) { @@ -174,6 +_,12 @@ entity.checkFallDistanceAccumulation(); @@ -98,4 +98,4 @@ + // Paper end - Expand EntityUnleashEvent } - default void closeRangeLeashBehaviour(Entity entity) { + default void closeRangeLeashBehaviour(final Entity leashHolder) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch index ebe1f9fbce02..5af35a432823 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/LightningBolt.java +++ b/net/minecraft/world/entity/LightningBolt.java -@@ -39,6 +_,7 @@ +@@ -40,6 +_,7 @@ private @Nullable ServerPlayer cause; private final Set hitEntities = Sets.newHashSet(); private int blocksSetOnFire; + public boolean isEffect; // Paper - Properly handle lightning effects api - public LightningBolt(EntityType type, Level level) { + public LightningBolt(final EntityType type, final Level level) { super(type, level); -@@ -75,7 +_,7 @@ +@@ -76,7 +_,7 @@ @Override public void tick() { super.tick(); @@ -17,7 +17,7 @@ if (this.level().isClientSide()) { this.level() .playLocalSound( -@@ -106,7 +_,7 @@ +@@ -107,7 +_,7 @@ } this.powerLightningRod(); @@ -26,7 +26,7 @@ this.gameEvent(GameEvent.LIGHTNING_STRIKE); } } -@@ -129,7 +_,7 @@ +@@ -130,7 +_,7 @@ } } @@ -35,7 +35,7 @@ } else if (this.life < -this.random.nextInt(10)) { this.flashes--; this.life = 1; -@@ -138,10 +_,10 @@ +@@ -139,10 +_,10 @@ } } @@ -48,28 +48,28 @@ List entities = this.level() .getEntities( this, -@@ -167,34 +_,43 @@ +@@ -168,34 +_,43 @@ } - private void spawnFire(int extraIgnitions) { -- if (!this.visualOnly && this.level() instanceof ServerLevel serverLevel) { -+ if (!this.visualOnly && !this.isEffect && this.level() instanceof ServerLevel serverLevel) { // Paper - Properly handle lightning effects api + private void spawnFire(final int additionalSources) { +- if (!this.visualOnly && this.level() instanceof ServerLevel level) { ++ if (!this.visualOnly && !this.isEffect && this.level() instanceof ServerLevel level) { // Paper - Properly handle lightning effects api BlockPos var7 = this.blockPosition(); - if (serverLevel.canSpreadFireAround(var7)) { - BlockState state = BaseFireBlock.getState(serverLevel, var7); - if (serverLevel.getBlockState(var7).isAir() && state.canSurvive(serverLevel, var7)) { + if (level.canSpreadFireAround(var7)) { + BlockState fire = BaseFireBlock.getState(level, var7); + if (level.getBlockState(var7).isAir() && fire.canSurvive(level, var7)) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), var7, this).isCancelled()) { // CraftBukkit - serverLevel.setBlockAndUpdate(var7, state); + level.setBlockAndUpdate(var7, fire); this.blocksSetOnFire++; + } // CraftBukkit } - for (int i = 0; i < extraIgnitions; i++) { - BlockPos blockPos1 = var7.offset(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1); - state = BaseFireBlock.getState(serverLevel, blockPos1); - if (serverLevel.getBlockState(blockPos1).isAir() && state.canSurvive(serverLevel, blockPos1)) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos1, this).isCancelled()) { // CraftBukkit - serverLevel.setBlockAndUpdate(blockPos1, state); + for (int i = 0; i < additionalSources; i++) { + BlockPos nearbyPos = var7.offset(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1); + fire = BaseFireBlock.getState(level, nearbyPos); + if (level.getBlockState(nearbyPos).isAir() && fire.canSurvive(level, nearbyPos)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), nearbyPos, this).isCancelled()) { // CraftBukkit + level.setBlockAndUpdate(nearbyPos, fire); this.blocksSetOnFire++; + } // CraftBukkit } @@ -78,60 +78,62 @@ } } -- private static void clearCopperOnLightningStrike(Level level, BlockPos pos) { -+ private static void clearCopperOnLightningStrike(Level level, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent - BlockState blockState = level.getBlockState(pos); - boolean flag = HoneycombItem.WAX_OFF_BY_BLOCK.get().get(blockState.getBlock()) != null; - boolean flag1 = blockState.getBlock() instanceof WeatheringCopper; - if (flag1 || flag) { - if (flag1) { -- level.setBlockAndUpdate(pos, WeatheringCopper.getFirst(level.getBlockState(pos))); +- private static void clearCopperOnLightningStrike(final Level level, final BlockPos struckPos) { ++ private static void clearCopperOnLightningStrike(final Level level, final BlockPos struckPos, final Entity lightning) { // Paper - Call EntityChangeBlockEvent + BlockState struckState = level.getBlockState(struckPos); + boolean isWaxed = HoneycombItem.WAX_OFF_BY_BLOCK.get().get(struckState.getBlock()) != null; + boolean isWeatheringCopper = struckState.getBlock() instanceof WeatheringCopper; + if (isWeatheringCopper || isWaxed) { + if (isWeatheringCopper) { +- level.setBlockAndUpdate(struckPos, WeatheringCopper.getFirst(level.getBlockState(struckPos))); + // Paper start - Call EntityChangeBlockEvent -+ BlockState newBlockState = WeatheringCopper.getFirst(level.getBlockState(pos)); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, pos, newBlockState)) { -+ level.setBlockAndUpdate(pos, newBlockState); ++ BlockState newBlockState = WeatheringCopper.getFirst(level.getBlockState(struckPos)); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, struckPos, newBlockState)) { ++ level.setBlockAndUpdate(struckPos, newBlockState); + } + // Paper end - Call EntityChangeBlockEvent } - BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); -@@ -202,16 +_,16 @@ + BlockPos.MutableBlockPos workPos = struckPos.mutable(); +@@ -204,18 +_,18 @@ - for (int i1 = 0; i1 < i; i1++) { - int i2 = level.random.nextInt(8) + 1; -- randomWalkCleaningCopper(level, pos, mutableBlockPos, i2); -+ randomWalkCleaningCopper(level, pos, mutableBlockPos, i2, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + for (int strike = 0; strike < strikesCount; strike++) { + int stepCount = random.nextInt(8) + 1; +- randomWalkCleaningCopper(level, struckPos, workPos, stepCount); ++ randomWalkCleaningCopper(level, struckPos, workPos, stepCount, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent } } } -- private static void randomWalkCleaningCopper(Level level, BlockPos pos, BlockPos.MutableBlockPos mutable, int steps) { -+ private static void randomWalkCleaningCopper(Level level, BlockPos pos, BlockPos.MutableBlockPos mutable, int steps, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - mutable.set(pos); + private static void randomWalkCleaningCopper( +- final Level level, final BlockPos originalStrikePos, final BlockPos.MutableBlockPos workPos, final int stepCount ++ final Level level, final BlockPos originalStrikePos, final BlockPos.MutableBlockPos workPos, final int stepCount, final Entity lightning // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + ) { + workPos.set(originalStrikePos); - for (int i = 0; i < steps; i++) { -- Optional optional = randomStepCleaningCopper(level, mutable); -+ Optional optional = randomStepCleaningCopper(level, mutable, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - if (optional.isEmpty()) { + for (int step = 0; step < stepCount; step++) { +- Optional stepPos = randomStepCleaningCopper(level, workPos); ++ Optional stepPos = randomStepCleaningCopper(level, workPos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + if (stepPos.isEmpty()) { break; } -@@ -220,11 +_,17 @@ +@@ -224,11 +_,17 @@ } } -- private static Optional randomStepCleaningCopper(Level level, BlockPos pos) { -+ private static Optional randomStepCleaningCopper(Level level, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - for (BlockPos blockPos : BlockPos.randomInCube(level.random, 10, pos, 1)) { - BlockState blockState = level.getBlockState(blockPos); - if (blockState.getBlock() instanceof WeatheringCopper) { -- WeatheringCopper.getPrevious(blockState).ifPresent(blockState1 -> level.setBlockAndUpdate(blockPos, blockState1)); +- private static Optional randomStepCleaningCopper(final Level level, final BlockPos pos) { ++ private static Optional randomStepCleaningCopper(final Level level, final BlockPos pos, final Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + for (BlockPos candidate : BlockPos.randomInCube(level.getRandom(), 10, pos, 1)) { + BlockState state = level.getBlockState(candidate); + if (state.getBlock() instanceof WeatheringCopper) { +- WeatheringCopper.getPrevious(state).ifPresent(s -> level.setBlockAndUpdate(candidate, s)); + // Paper start - call EntityChangeBlockEvent -+ WeatheringCopper.getPrevious(blockState).ifPresent(blockState1 -> { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, blockPos, blockState1)) { -+ level.setBlockAndUpdate(blockPos, blockState1); ++ WeatheringCopper.getPrevious(state).ifPresent(s -> { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, candidate, s)) { ++ level.setBlockAndUpdate(candidate, s); + } + }); + // Paper end - call EntityChangeBlockEvent - level.levelEvent(LevelEvent.PARTICLES_ELECTRIC_SPARK, blockPos, -1); - return Optional.of(blockPos); + level.levelEvent(LevelEvent.PARTICLES_ELECTRIC_SPARK, candidate, -1); + return Optional.of(candidate); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index e763a6ef5cad..a8e0bfd75079 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -143,6 +_,17 @@ +@@ -140,6 +_,17 @@ import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -18,10 +18,10 @@ public abstract class LivingEntity extends Entity implements Attackable, WaypointTransmitter { private static final Logger LOGGER = LogUtils.getLogger(); private static final String TAG_ACTIVE_EFFECTS = "active_effects"; -@@ -268,11 +_,25 @@ - ); - protected final EntityEquipment equipment; +@@ -269,11 +_,25 @@ private Waypoint.Icon locatorBarIcon = new Waypoint.Icon(); + public @Nullable Vec3 currentImpulseImpactPos; + public @Nullable Entity currentExplosionCause; + // CraftBukkit start + public int expToDrop; + public List drops = new java.util.ArrayList<>(); // Paper - Restore vanilla drops behavior @@ -35,7 +35,7 @@ + public int invulnerableDuration = LivingEntity.INVULNERABLE_DURATION; // Paper - configurable invulnerable duration + // CraftBukkit end - protected LivingEntity(EntityType type, Level level) { + protected LivingEntity(final EntityType type, final Level level) { super(type, level); this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type)); - this.setHealth(this.getMaxHealth()); @@ -45,22 +45,21 @@ this.equipment = this.createEquipment(); this.blocksBuilding = true; this.reapplyPosition(); -@@ -371,7 +_,13 @@ +@@ -365,7 +_,13 @@ - double d1 = Math.min(0.2F + d / 15.0, 2.5); - int i = (int)(150.0 * d1); -- serverLevel.sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, state), x, y1, z, i, 0.0, 0.0, 0.0, 0.15F); + double scale = Math.min(0.2F + power / 15.0, 2.5); + int particles = (int)(150.0 * scale); + // CraftBukkit start - visibility api + if (this instanceof ServerPlayer) { -+ serverLevel.sendParticlesSource((ServerPlayer) this, new BlockParticleOption(ParticleTypes.BLOCK, state), false, false, x, y1, z, i, 0.0, 0.0, 0.0, 0.15F); ++ level.sendParticlesSource((ServerPlayer)this, new BlockParticleOption(ParticleTypes.BLOCK, onState), false, false, x, y, z, particles, 0.0, 0.0, 0.0, 0.15F); + } else { -+ serverLevel.sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, state), x, y1, z, i, 0.0, 0.0, 0.0, 0.15F); + level.sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, onState), x, y, z, particles, 0.0, 0.0, 0.0, 0.15F); + } + // CraftBukkit end } } -@@ -556,7 +_,7 @@ +@@ -550,7 +_,7 @@ this.deathTime++; if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) { this.level().broadcastEntityEvent(this, EntityEvent.POOF); @@ -69,7 +68,7 @@ } } -@@ -658,7 +_,7 @@ +@@ -652,7 +_,7 @@ } public boolean shouldDiscardFriction() { @@ -77,32 +76,32 @@ + return !this.frictionState.toBooleanOrElse(!this.discardFriction); // Paper - Friction API } - public void setDiscardFriction(boolean discardFriction) { -@@ -670,10 +_,15 @@ + public void setDiscardFriction(final boolean discardFriction) { +@@ -664,10 +_,15 @@ } - public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem) { + public void onEquipItem(final EquipmentSlot slot, final ItemStack oldStack, final ItemStack stack) { + // CraftBukkit start -+ this.onEquipItem(slot, oldItem, newItem, false); ++ this.onEquipItem(slot, oldStack, stack, false); + } -+ public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem, boolean silent) { ++ public void onEquipItem(final EquipmentSlot slot, final ItemStack oldStack, final ItemStack stack, final boolean silent) { + // CraftBukkit end if (!this.level().isClientSide() && !this.isSpectator()) { - if (!ItemStack.isSameItemSameComponents(oldItem, newItem) && !this.firstTick) { - Equippable equippable = newItem.get(DataComponents.EQUIPPABLE); + if (!ItemStack.isSameItemSameComponents(oldStack, stack) && !this.firstTick) { + Equippable equippable = stack.get(DataComponents.EQUIPPABLE); - if (!this.isSilent() && equippable != null && slot == equippable.slot()) { + if (!this.isSilent() && equippable != null && slot == equippable.slot() && !silent) { // CraftBukkit this.level() .playSeededSound( null, -@@ -700,12 +_,12 @@ +@@ -694,12 +_,12 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause - if ((reason == Entity.RemovalReason.KILLED || reason == Entity.RemovalReason.DISCARDED) && this.level() instanceof ServerLevel serverLevel) { - this.triggerOnDeathMobEffects(serverLevel, reason); +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause + if ((reason == Entity.RemovalReason.KILLED || reason == Entity.RemovalReason.DISCARDED) && this.level() instanceof ServerLevel level) { + this.triggerOnDeathMobEffects(level, reason); } - super.remove(reason); @@ -110,8 +109,8 @@ this.brain.clearMemories(); } -@@ -722,11 +_,17 @@ - mobEffectInstance.onMobRemoved(level, this, removalReason); +@@ -716,11 +_,17 @@ + effect.onMobRemoved(level, this, reason); } + this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DEATH); // CraftBukkit @@ -119,7 +118,7 @@ } @Override - protected void addAdditionalSaveData(ValueOutput output) { + protected void addAdditionalSaveData(final ValueOutput output) { + // Paper start - Friction API + if (this.frictionState != net.kyori.adventure.util.TriState.NOT_SET) { + output.putString("Paper.FrictionState", this.frictionState.toString()); @@ -128,38 +127,38 @@ output.putFloat("Health", this.getHealth()); output.putShort("HurtTime", (short)this.hurtTime); output.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp); -@@ -760,7 +_,12 @@ +@@ -755,7 +_,12 @@ } } -- public @Nullable ItemEntity drop(ItemStack stack, boolean randomizeMotion, boolean includeThrower) { +- public @Nullable ItemEntity drop(final ItemStack itemStack, final boolean randomly, final boolean thrownFromHand) { + // Paper start - Extend dropItem API -+ public final @Nullable ItemEntity drop(ItemStack stack, boolean randomizeMotion, boolean includeThrower) { -+ return this.drop(stack, randomizeMotion, includeThrower, true, null); ++ public final @Nullable ItemEntity drop(final ItemStack itemStack, final boolean randomly, final boolean thrownFromHand) { ++ return this.drop(itemStack, randomly, thrownFromHand, true, null); + } -+ public @Nullable ItemEntity drop(ItemStack stack, boolean randomizeMotion, boolean includeThrower, boolean callEvent, java.util.function.@Nullable Consumer entityOperation) { ++ public @Nullable ItemEntity drop(final ItemStack itemStack, final boolean randomly, final boolean thrownFromHand, final boolean callEvent, final java.util.function.@Nullable Consumer entityOperation) { + // Paper end - Extend dropItem API - if (stack.isEmpty()) { + if (itemStack.isEmpty()) { return null; } else if (this.level().isClientSide()) { -@@ -769,6 +_,31 @@ +@@ -764,6 +_,31 @@ } else { - ItemEntity itemEntity = this.createItemStackToDrop(stack, randomizeMotion, includeThrower); - if (itemEntity != null) { + ItemEntity entity = this.createItemStackToDrop(itemStack, randomly, thrownFromHand); + if (entity != null) { + // CraftBukkit start - fire PlayerDropItemEvent -+ if (entityOperation != null) entityOperation.accept((org.bukkit.entity.Item) itemEntity.getBukkitEntity()); ++ if (entityOperation != null) entityOperation.accept((org.bukkit.entity.Item) entity.getBukkitEntity()); + if (callEvent && this.getBukkitEntity() instanceof org.bukkit.entity.Player player) { -+ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) itemEntity.getBukkitEntity(); ++ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) entity.getBukkitEntity(); + + org.bukkit.event.player.PlayerDropItemEvent event = new org.bukkit.event.player.PlayerDropItemEvent(player, drop); + this.level().getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + org.bukkit.inventory.ItemStack inHandItem = player.getInventory().getItemInMainHand(); -+ if (includeThrower && inHandItem.getAmount() == 0) { ++ if (thrownFromHand && inHandItem.getAmount() == 0) { + // The complete stack was dropped + player.getInventory().setItemInMainHand(drop.getItemStack()); -+ } else if (includeThrower && inHandItem.isSimilar(drop.getItemStack()) && inHandItem.getAmount() < inHandItem.getMaxStackSize() && drop.getItemStack().getAmount() == 1) { ++ } else if (thrownFromHand && inHandItem.isSimilar(drop.getItemStack()) && inHandItem.getAmount() < inHandItem.getMaxStackSize() && drop.getItemStack().getAmount() == 1) { + // Only one item is dropped + inHandItem.setAmount(inHandItem.getAmount() + 1); + player.getInventory().setItemInMainHand(inHandItem); @@ -171,13 +170,13 @@ + } + } + // CraftBukkit end - this.level().addFreshEntity(itemEntity); + this.level().addFreshEntity(entity); } -@@ -778,7 +_,22 @@ +@@ -773,7 +_,22 @@ @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { - this.internalSetAbsorptionAmount(input.getFloatOr("AbsorptionAmount", 0.0F)); + // Paper start - Check for NaN + float absorptionAmount = input.getFloatOr("AbsorptionAmount", 0.0F); @@ -198,7 +197,7 @@ if (this.level() != null && !this.level().isClientSide()) { input.read("attributes", AttributeInstance.Packed.LIST_CODEC).ifPresent(this.getAttributes()::apply); } -@@ -791,6 +_,11 @@ +@@ -786,6 +_,11 @@ this.effectsDirty = true; } @@ -210,29 +209,29 @@ this.setHealth(input.getFloatOr("Health", this.getMaxHealth())); this.hurtTime = input.getShortOr("HurtTime", (short)0); this.deathTime = input.getShortOr("DeathTime", (short)0); -@@ -798,6 +_,7 @@ - input.getString("Team").ifPresent(string -> { +@@ -793,6 +_,7 @@ + input.getString("Team").ifPresent(teamName -> { Scoreboard scoreboard = this.level().getScoreboard(); - PlayerTeam playerTeam = scoreboard.getPlayerTeam(string); -+ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { playerTeam = null; } // Paper - Perf: Disable Scoreboards for non players by default - boolean flag = playerTeam != null && scoreboard.addPlayerToTeam(this.getStringUUID(), playerTeam); - if (!flag) { - LOGGER.warn("Unable to add mob to team \"{}\" (that team probably doesn't exist)", string); -@@ -805,11 +_,13 @@ + PlayerTeam team = scoreboard.getPlayerTeam(teamName); ++ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { team = null; } // Paper - Perf: Disable Scoreboards for non players by default + boolean success = team != null && scoreboard.addPlayerToTeam(this.getStringUUID(), team); + if (!success) { + LOGGER.warn("Unable to add mob to team \"{}\" (that team probably doesn't exist)", teamName); +@@ -800,11 +_,13 @@ }); this.setSharedFlag(Entity.FLAG_FALL_FLYING, input.getBooleanOr("FallFlying", false)); - input.read("sleeping_pos", BlockPos.CODEC).ifPresentOrElse(blockPos -> { -+ if (this.position().distanceToSqr(blockPos.getX(), blockPos.getY(), blockPos.getZ()) < Mth.square(16)) { // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong - this.setSleepingPos(blockPos); + input.read("sleeping_pos", BlockPos.CODEC).ifPresentOrElse(sleepingPos -> { ++ if (this.position().distanceToSqr(sleepingPos.getX(), sleepingPos.getY(), sleepingPos.getZ()) < Mth.square(16)) { // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong + this.setSleepingPos(sleepingPos); this.entityData.set(DATA_POSE, Pose.SLEEPING); if (!this.firstTick) { - this.setPosToBed(blockPos); + this.setPosToBed(sleepingPos); } + } // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong }, this::clearSleepingPos); - input.read("Brain", Codec.PASSTHROUGH).ifPresent(dynamic -> this.brain = this.makeBrain((Dynamic)dynamic)); + input.read("Brain", Brain.Packed.CODEC).ifPresent(packedBrain -> this.brain = this.makeBrain(packedBrain)); this.lastHurtByPlayer = EntityReference.read(input, "last_hurt_by_player"); -@@ -826,15 +_,44 @@ +@@ -823,15 +_,44 @@ this.updateDirtyEffects(); } @@ -265,19 +264,19 @@ + this.isTickingEffects = true; // CraftBukkit try { while (iterator.hasNext()) { - Holder holder = iterator.next(); - MobEffectInstance mobEffectInstance = this.activeEffects.get(holder); - if (!mobEffectInstance.tickServer(serverLevel, this, () -> this.onEffectUpdated(mobEffectInstance, true, null))) { + Holder mobEffect = iterator.next(); + MobEffectInstance effect = this.activeEffects.get(mobEffect); + if (!effect.tickServer(serverLevel, this, () -> this.onEffectUpdated(effect, true, null))) { + // CraftBukkit start -+ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobEffectInstance, null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.EXPIRATION); ++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.EXPIRATION); + if (event.isCancelled()) { + continue; + } + // CraftBukkit end iterator.remove(); - this.onEffectsRemoved(List.of(mobEffectInstance)); - } else if (mobEffectInstance.getDuration() % 600 == 0) { -@@ -843,6 +_,18 @@ + this.onEffectsRemoved(List.of(effect)); + } else if (effect.getDuration() % 600 == 0) { +@@ -840,6 +_,18 @@ } } catch (ConcurrentModificationException var6) { } @@ -294,9 +293,9 @@ + this.effectsToProcess.clear(); + // CraftBukkit end } else { - for (MobEffectInstance mobEffectInstance1 : this.activeEffects.values()) { - mobEffectInstance1.tickClient(); -@@ -953,15 +_,33 @@ + for (MobEffectInstance effect : this.activeEffects.values()) { + effect.tickClient(); +@@ -950,15 +_,33 @@ } public boolean removeAllEffects() { @@ -310,9 +309,9 @@ } else if (this.activeEffects.isEmpty()) { return false; } else { -- Map, MobEffectInstance> map = Maps.newHashMap(this.activeEffects); +- Map, MobEffectInstance> copy = Maps.newHashMap(this.activeEffects); - this.activeEffects.clear(); -- this.onEffectsRemoved(map.values()); +- this.onEffectsRemoved(copy.values()); - return true; + // CraftBukkit start + List toRemove = new java.util.LinkedList<>(); @@ -334,88 +333,88 @@ } } -@@ -987,23 +_,71 @@ +@@ -984,23 +_,71 @@ } - public final boolean addEffect(MobEffectInstance effectInstance) { -- return this.addEffect(effectInstance, null); -+ return this.addEffect(effectInstance, (Entity) null); // CraftBukkit + public final boolean addEffect(final MobEffectInstance newEffect) { +- return this.addEffect(newEffect, null); ++ return this.addEffect(newEffect, (Entity)null); // CraftBukkit + } + + // CraftBukkit start -+ public boolean addEffect(MobEffectInstance effectInstance, EntityPotionEffectEvent.Cause cause) { -+ return this.addEffect(effectInstance, (Entity) null, cause); ++ public boolean addEffect(final MobEffectInstance newEffect, final EntityPotionEffectEvent.Cause cause) { ++ return this.addEffect(newEffect, (Entity)null, cause); } - public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity) { -+ return this.addEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + public boolean addEffect(final MobEffectInstance newEffect, final @Nullable Entity source) { ++ return this.addEffect(newEffect, source, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + } + -+ public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { ++ public boolean addEffect(final MobEffectInstance newEffect, final @Nullable Entity source, final EntityPotionEffectEvent.Cause cause) { + // Paper start - Don't fire sync event during generation -+ return this.addEffect(effectInstance, entity, cause, true); ++ return this.addEffect(newEffect, source, cause, true); + } -+ public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) { ++ public boolean addEffect(final MobEffectInstance newEffect, final @Nullable Entity source, final EntityPotionEffectEvent.Cause cause, final boolean fireEvent) { + // Paper end - Don't fire sync event during generation + // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API + if (this.isTickingEffects) { -+ this.effectsToProcess.add(new ProcessableEffect(effectInstance, cause)); ++ this.effectsToProcess.add(new ProcessableEffect(newEffect, cause)); + return true; + } + // CraftBukkit end - if (!this.canBeAffected(effectInstance)) { + if (!this.canBeAffected(newEffect)) { return false; } else { - MobEffectInstance mobEffectInstance = this.activeEffects.get(effectInstance.getEffect()); - boolean flag = false; + MobEffectInstance effect = this.activeEffects.get(newEffect.getEffect()); + boolean changed = false; + // CraftBukkit start + boolean override = false; + // Paper start - Properly update hidden effects + boolean addAsHiddenEffect = false; -+ if (mobEffectInstance != null) { -+ override = new MobEffectInstance(mobEffectInstance).update(effectInstance); -+ addAsHiddenEffect = mobEffectInstance.getAmplifier() > effectInstance.getAmplifier() && mobEffectInstance.isShorterDurationThan(effectInstance); ++ if (effect != null) { ++ override = new MobEffectInstance(effect).update(newEffect); ++ addAsHiddenEffect = effect.getAmplifier() > newEffect.getAmplifier() && effect.isShorterDurationThan(newEffect); + // Paper end - Properly update hidden effects + } + + if (fireEvent) { // Paper - Don't fire sync event during generation -+ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobEffectInstance, effectInstance, cause, override); ++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, newEffect, cause, override); + override = event.isOverride(); // Paper - Don't fire sync event during generation + if (event.isCancelled()) { + return false; + } + } // Paper - Don't fire sync event during generation + // CraftBukkit end - if (mobEffectInstance == null) { - this.activeEffects.put(effectInstance.getEffect(), effectInstance); - this.onEffectAdded(effectInstance, entity); - flag = true; - effectInstance.onEffectAdded(this); -- } else if (mobEffectInstance.update(effectInstance)) { + if (effect == null) { + this.activeEffects.put(newEffect.getEffect(), newEffect); + this.onEffectAdded(newEffect, source); + changed = true; + newEffect.onEffectAdded(this); +- } else if (effect.update(newEffect)) { + // CraftBukkit start + } else if (override) { // Paper - Don't fire sync event during generation -+ mobEffectInstance.update(effectInstance); - this.onEffectUpdated(mobEffectInstance, true, entity); - flag = true; ++ effect.update(newEffect); + this.onEffectUpdated(effect, true, source); + changed = true; + // Paper start - Properly update hidden effects + } else if (addAsHiddenEffect) { -+ if (mobEffectInstance.hiddenEffect == null) { -+ mobEffectInstance.hiddenEffect = new MobEffectInstance(effectInstance); ++ if (effect.hiddenEffect == null) { ++ effect.hiddenEffect = new MobEffectInstance(newEffect); + } else { -+ mobEffectInstance.hiddenEffect.update(effectInstance); ++ effect.hiddenEffect.update(newEffect); + } + // Paper end - Properly update hidden effects } - effectInstance.onEffectStarted(this); -@@ -1039,11 +_,35 @@ + newEffect.onEffectStarted(this); +@@ -1035,11 +_,35 @@ } - public final @Nullable MobEffectInstance removeEffectNoUpdate(Holder effect) { + public final @Nullable MobEffectInstance removeEffectNoUpdate(final Holder effect) { + // CraftBukkit start + return this.removeEffectNoUpdate(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + } -+ public @Nullable MobEffectInstance removeEffectNoUpdate(Holder effect, EntityPotionEffectEvent.Cause cause) { ++ public @Nullable MobEffectInstance removeEffectNoUpdate(final Holder effect, final EntityPotionEffectEvent.Cause cause) { + if (this.isTickingEffects) { + this.effectsToProcess.add(new ProcessableEffect(effect, cause)); + return null; @@ -434,36 +433,36 @@ return this.activeEffects.remove(effect); } - public boolean removeEffect(Holder effect) { -- MobEffectInstance mobEffectInstance = this.removeEffectNoUpdate(effect); + public boolean removeEffect(final Holder effect) { +- MobEffectInstance effectInstance = this.removeEffectNoUpdate(effect); + return this.removeEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + } + -+ public boolean removeEffect(Holder effect, EntityPotionEffectEvent.Cause cause) { -+ MobEffectInstance mobEffectInstance = this.removeEffectNoUpdate(effect, cause); ++ public boolean removeEffect(final Holder effect, final EntityPotionEffectEvent.Cause cause) { ++ MobEffectInstance effectInstance = this.removeEffectNoUpdate(effect, cause); + // CraftBukkit end - if (mobEffectInstance != null) { - this.onEffectsRemoved(List.of(mobEffectInstance)); + if (effectInstance != null) { + this.onEffectsRemoved(List.of(effectInstance)); return true; -@@ -1134,17 +_,62 @@ +@@ -1130,17 +_,62 @@ } - public void heal(float amount) { + public void heal(final float heal) { + // CraftBukkit start - Delegate so we can handle providing a reason for health being regained -+ this.heal(amount, EntityRegainHealthEvent.RegainReason.CUSTOM); ++ this.heal(heal, EntityRegainHealthEvent.RegainReason.CUSTOM); + } + -+ public void heal(float amount, EntityRegainHealthEvent.RegainReason regainReason) { ++ public void heal(final float heal, final EntityRegainHealthEvent.RegainReason regainReason) { + // Paper start - Forward -+ this.heal(amount, regainReason, false); ++ this.heal(heal, regainReason, false); + } + -+ public void heal(float amount, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) { ++ public void heal(final float heal, final EntityRegainHealthEvent.RegainReason regainReason, final boolean isFastRegen) { + // Paper end - Forward float health = this.getHealth(); if (health > 0.0F) { -- this.setHealth(health + amount); -+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), amount, regainReason, isFastRegen); // Paper +- this.setHealth(health + heal); ++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), heal, regainReason, isFastRegen); // Paper + // Suppress during worldgen + if (this.valid) { + this.level().getCraftServer().getPluginManager().callEvent(event); @@ -485,8 +484,9 @@ return this.entityData.get(DATA_HEALTH_ID); } - public void setHealth(float health) { -+ // Paper start - Check for NaN +- public void setHealth(final float health) { ++ // Paper start - Check for NaN ++ public void setHealth(float health) { + if (Float.isNaN(health)) { health = getMaxHealth(); if (this.valid) { + System.err.println("[NAN-HEALTH] " + getScoreboardName() + " had NaN health set"); + } } // Paper end - Check for NaN @@ -495,7 +495,7 @@ + org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity(); + // Squeeze + if (health < 0.0F) { -+ player.setRealHealth(0.0D); ++ player.setRealHealth(0.0); + } else if (health > player.getMaxHealth()) { + player.setRealHealth(player.getMaxHealth()); + } else { @@ -509,177 +509,177 @@ this.entityData.set(DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1156,7 +_,7 @@ - public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { - if (this.isInvulnerableTo(level, damageSource)) { +@@ -1152,7 +_,7 @@ + public boolean hurtServer(final ServerLevel level, final DamageSource source, float damage) { + if (this.isInvulnerableTo(level, source)) { return false; - } else if (this.isDeadOrDying()) { + } else if (this.isRemoved() || this.dead || this.getHealth() <= 0.0F) { // CraftBukkit - Don't allow entities that got set to dead/killed elsewhere to get damaged and die return false; - } else if (damageSource.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { + } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1172,35 +_,58 @@ - - ItemStack useItem = this.getUseItem(); - float originAmount = amount; -- float f1 = this.applyItemBlocking(level, damageSource, amount); -- amount -= f1; -+ float f1 = this.applyItemBlocking(level, damageSource, amount, true); // Paper -+ // amount -= f1; // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to allow modification - boolean flag = f1 > 0.0F; -- if (damageSource.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { +@@ -1168,35 +_,58 @@ + + ItemStack itemInUse = this.getUseItem(); + float originalDamage = damage; +- float damageBlocked = this.applyItemBlocking(level, source, damage); +- damage -= damageBlocked; ++ float damageBlocked = this.applyItemBlocking(level, source, damage, true); // Paper ++ // damage -= damageBlocked; // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to allow modification + boolean blocked = damageBlocked > 0.0F; +- if (source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { + // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount -+ if (false && damageSource.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { - amount *= 5.0F; ++ if (false && source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { + damage *= 5.0F; } -- if (damageSource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { +- if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount and actuallyHurt(DamageSource, float, EntityDamageEvent) for handle damage -+ if (false && damageSource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - this.hurtHelmet(damageSource, amount); - amount *= 0.75F; ++ if (false && source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + this.hurtHelmet(source, damage); + damage *= 0.75F; } + EntityDamageEvent event; // CraftBukkit // Paper - move this into the actual invuln check.... - if (Float.isNaN(amount) || Float.isInfinite(amount)) { - amount = Float.MAX_VALUE; + if (Float.isNaN(damage) || Float.isInfinite(damage)) { + damage = Float.MAX_VALUE; } - boolean flag1 = true; -- if (this.invulnerableTime > 10.0F && !damageSource.is(DamageTypeTags.BYPASSES_COOLDOWN)) { -+ if (this.invulnerableTime > (float) this.invulnerableDuration / 2.0F && !damageSource.is(DamageTypeTags.BYPASSES_COOLDOWN)) { // CraftBukkit - restore use of maxNoDamageTicks - if (amount <= this.lastHurt) { + boolean tookFullDamage = true; +- if (this.invulnerableTime > 10.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { ++ if (this.invulnerableTime > (float)this.invulnerableDuration / 2.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { // CraftBukkit - restore use of maxNoDamageTicks + if (damage <= this.lastHurt) { return false; } -- this.actuallyHurt(level, damageSource, amount - this.lastHurt); +- this.actuallyHurt(level, source, damage - this.lastHurt); + // Paper start - only call damage event when actuallyHurt will be called - move call logic down -+ event = this.handleEntityDamage(damageSource, amount, this.lastHurt); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction -+ amount = computeAmountFromEntityDamageEvent(event); ++ event = this.handleEntityDamage(source, damage, this.lastHurt); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction ++ damage = this.computeAmountFromEntityDamageEvent(event); + // Paper end - only call damage event when actuallyHurt will be called - move call logic down + + // CraftBukkit start -+ if (!this.actuallyHurt(level, damageSource, (float) event.getFinalDamage(), event)) { // Paper - fix invulnerability reduction in EntityDamageEvent - no longer subtract lastHurt, that is part of the damage event calc now ++ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { // Paper - fix invulnerability reduction in EntityDamageEvent - no longer subtract lastHurt, that is part of the damage event calc now + return false; + } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + // CraftBukkit end - this.lastHurt = amount; - flag1 = false; + this.lastHurt = damage; + tookFullDamage = false; } else { + // Paper start - only call damage event when actuallyHurt will be called - move call logic down -+ event = this.handleEntityDamage(damageSource, amount, 0); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction (none in this branch) -+ amount = computeAmountFromEntityDamageEvent(event); ++ event = this.handleEntityDamage(source, damage, 0); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction (none in this branch) ++ damage = this.computeAmountFromEntityDamageEvent(event); + // Paper end - only call damage event when actuallyHurt will be called - move call logic down + // CraftBukkit start -+ if (!this.actuallyHurt(level, damageSource, (float) event.getFinalDamage(), event)) { ++ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { + return false; + } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - this.lastHurt = amount; ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + this.lastHurt = damage; - this.invulnerableTime = 20; -- this.actuallyHurt(level, damageSource, amount); +- this.actuallyHurt(level, source, damage); + this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks -+ // this.actuallyHurt(level, damageSource, amount); ++ // this.actuallyHurt(level, source, damage); + // CraftBukkit end this.hurtDuration = 10; this.hurtTime = this.hurtDuration; } -@@ -1215,7 +_,7 @@ - level.broadcastDamageEvent(this, damageSource); +@@ -1211,7 +_,7 @@ + level.broadcastDamageEvent(this, source); } -- if (!damageSource.is(DamageTypeTags.NO_IMPACT) && (!flag || amount > 0.0F)) { -+ if (!damageSource.is(DamageTypeTags.NO_IMPACT) && !flag) { // CraftBukkit - Prevent marking hurt if the damage is blocked +- if (!source.is(DamageTypeTags.NO_IMPACT) && (!blocked || damage > 0.0F)) { ++ if (!source.is(DamageTypeTags.NO_IMPACT) && !blocked) { // CraftBukkit - Prevent marking hurt if the damage is blocked this.markHurt(); } -@@ -1230,8 +_,16 @@ - d = damageSource.getSourcePosition().x() - this.getX(); - d1 = damageSource.getSourcePosition().z() - this.getZ(); +@@ -1226,8 +_,16 @@ + xd = source.getSourcePosition().x() - this.getX(); + zd = source.getSourcePosition().z() - this.getZ(); } + // Paper start - Check distance in entity interactions; see for loop in knockback method -+ if (Math.abs(d) > 200) { -+ d = Math.random() - Math.random(); ++ if (Math.abs(xd) > 200) { ++ xd = Math.random() - Math.random(); + } -+ if (Math.abs(d1) > 200) { -+ d1 = Math.random() - Math.random(); ++ if (Math.abs(zd) > 200) { ++ zd = Math.random() - Math.random(); + } + // Paper end - Check distance in entity interactions -- this.knockback(0.4F, d, d1); -+ this.knockback(0.4F, d, d1, damageSource.getDirectEntity(), damageSource.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events - if (!flag) { - this.indicateDamage(d, d1); +- this.knockback(0.4F, xd, zd); ++ this.knockback(0.4F, xd, zd, source.getDirectEntity(), source.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events + if (!blocked) { + this.indicateDamage(xd, zd); } -@@ -1240,19 +_,19 @@ +@@ -1236,19 +_,19 @@ if (this.isDeadOrDying()) { - if (!this.checkTotemDeathProtection(damageSource)) { -- if (flag1) { + if (!this.checkTotemDeathProtection(source)) { +- if (tookFullDamage) { - this.makeSound(this.getDeathSound()); -- this.playSecondaryHurtSound(damageSource); +- this.playSecondaryHurtSound(source); - } + // Paper start - moved into CraftEventFactory event caller for cancellable death event -+ this.silentDeath = !flag1; // mark entity as dying silently ++ this.silentDeath = !tookFullDamage; // mark entity as dying silently + // Paper end - this.die(damageSource); + this.die(source); + this.silentDeath = false; // Paper - cancellable death event - reset to default } - } else if (flag1) { - this.playHurtSound(damageSource); - this.playSecondaryHurtSound(damageSource); + } else if (tookFullDamage) { + this.playHurtSound(source); + this.playSecondaryHurtSound(source); } -- boolean flag2 = !flag || amount > 0.0F; -+ boolean flag2 = !flag; // CraftBukkit - Ensure to return false if damage is blocked - if (flag2) { - this.lastDamageSource = damageSource; +- boolean success = !blocked || damage > 0.0F; ++ boolean success = !blocked; // CraftBukkit - Ensure to return false if damage is blocked + if (success) { + this.lastDamageSource = source; this.lastDamageStamp = this.level().getGameTime(); -@@ -1278,6 +_,12 @@ +@@ -1274,6 +_,12 @@ } - public float applyItemBlocking(ServerLevel level, DamageSource damageSource, float damageAmount) { + public float applyItemBlocking(final ServerLevel level, final DamageSource source, final float damage) { + // Paper start -+ return applyItemBlocking(level, damageSource, damageAmount, false); ++ return this.applyItemBlocking(level, source, damage, false); + } + -+ public float applyItemBlocking(ServerLevel level, DamageSource damageSource, float damageAmount, boolean dryRun) { ++ public float applyItemBlocking(final ServerLevel level, final DamageSource source, final float damage, final boolean dryRun) { + // Paper end - if (damageAmount <= 0.0F) { + if (damage <= 0.0F) { return 0.0F; } else { -@@ -1302,10 +_,12 @@ +@@ -1298,10 +_,12 @@ } - float f = blocksAttacks.resolveBlockedDamage(damageSource, damageAmount, acos); + float damageBlocked = blocksAttacks.resolveBlockedDamage(source, damage, angle); + if (!dryRun) { // Paper - blocksAttacks.hurtBlockingItem(this.level(), itemBlockingWith, this, this.getUsedItemHand(), f); -- if (f > 0.0F && !damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity) { -+ if (f > 0.0F && !damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions + blocksAttacks.hurtBlockingItem(this.level(), blockingWith, this, this.getUsedItemHand(), damageBlocked); +- if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity) { ++ if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions this.blockUsingItem(level, livingEntity); } + } // Paper - return f; + return damageBlocked; } -@@ -1316,6 +_,59 @@ +@@ -1312,6 +_,59 @@ } } + // Paper start - copied from above split by relevant part -+ public boolean canBlockAttack(DamageSource damageSource, float damageAmount) { -+ if (damageAmount <= 0.0F) { ++ public boolean canBlockAttack(DamageSource source, float damage) { ++ if (damage <= 0.0F) { + return false; + } else { -+ ItemStack itemBlockingWith = this.getItemBlockingWith(); -+ if (itemBlockingWith == null) { ++ ItemStack blockingWith = this.getItemBlockingWith(); ++ if (blockingWith == null) { + return false; + } else { -+ BlocksAttacks blocksAttacks = itemBlockingWith.get(DataComponents.BLOCKS_ATTACKS); -+ if (blocksAttacks != null && !blocksAttacks.bypassedBy().map(damageSource::is).orElse(false)) { -+ if (damageSource.getDirectEntity() instanceof AbstractArrow abstractArrow && abstractArrow.getPierceLevel() > 0) { ++ BlocksAttacks blocksAttacks = blockingWith.get(DataComponents.BLOCKS_ATTACKS); ++ if (blocksAttacks != null && !blocksAttacks.bypassedBy().map(t -> t.contains(source.typeHolder())).orElse(false)) { ++ if (source.getDirectEntity() instanceof AbstractArrow abstractArrow && abstractArrow.getPierceLevel() > 0) { + return false; + } else { + return true; @@ -715,16 +715,16 @@ + if (blocksAttacks == null) return; + + blocksAttacks.hurtBlockingItem(this.level(), itemBlockingWith, this, this.getUsedItemHand(), f); -+ if (f > 0.0F && !damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions ++ if (f > 0.0F && !damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions + this.blockUsingItem(level, livingEntity); + } + } + // Paper end - copied from above split by relevant part + - public void playSecondaryHurtSound(DamageSource damageSource) { - if (damageSource.is(DamageTypes.THORNS)) { + public void playSecondaryHurtSound(final DamageSource source) { + if (source.is(DamageTypes.THORNS)) { SoundSource soundSource = this instanceof Player ? SoundSource.PLAYERS : SoundSource.HOSTILE; -@@ -1347,12 +_,24 @@ +@@ -1343,12 +_,24 @@ return EntityReference.getPlayer(this.lastHurtByPlayer, this.level()); } @@ -740,72 +740,72 @@ + } + // Paper end - only call damage event when actuallyHurt will be called - move out amount computation logic + - protected void blockUsingItem(ServerLevel level, LivingEntity entity) { - entity.blockedByItem(this); + protected void blockUsingItem(final ServerLevel level, final LivingEntity attacker) { + attacker.blockedByItem(this); } - protected void blockedByItem(LivingEntity entity) { -- entity.knockback(0.5, entity.getX() - this.getX(), entity.getZ() - this.getZ()); -+ entity.knockback(0.5, entity.getX() - this.getX(), entity.getZ() - this.getZ(), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker & knockback events + protected void blockedByItem(final LivingEntity defender) { +- defender.knockback(0.5, defender.getX() - this.getX(), defender.getZ() - this.getZ()); ++ defender.knockback(0.5, defender.getX() - this.getX(), defender.getZ() - this.getZ(), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker & knockback events } - private boolean checkTotemDeathProtection(DamageSource damageSource) { -@@ -1362,18 +_,39 @@ - ItemStack itemStack = null; - DeathProtection deathProtection = null; + private boolean checkTotemDeathProtection(final DamageSource killingDamage) { +@@ -1358,18 +_,39 @@ + ItemStack protectionItem = null; + DeathProtection protection = null; + // CraftBukkit start -+ InteractionHand hand = null; -+ ItemStack itemInHand = ItemStack.EMPTY; - for (InteractionHand interactionHand : InteractionHand.values()) { -- ItemStack itemInHand = this.getItemInHand(interactionHand); -+ itemInHand = this.getItemInHand(interactionHand); - deathProtection = itemInHand.get(DataComponents.DEATH_PROTECTION); - if (deathProtection != null) { -+ hand = interactionHand; // CraftBukkit - itemStack = itemInHand.copy(); -+ // itemInHand.shrink(1); // CraftBukkit ++ InteractionHand usedHand = null; ++ ItemStack itemStack = ItemStack.EMPTY; + for (InteractionHand hand : InteractionHand.values()) { +- ItemStack itemStack = this.getItemInHand(hand); ++ itemStack = this.getItemInHand(hand); + protection = itemStack.get(DataComponents.DEATH_PROTECTION); + if (protection != null) { ++ usedHand = hand; + protectionItem = itemStack.copy(); ++ // itemStack.shrink(1); + break; + } + } + -+ final org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null; ++ final org.bukkit.inventory.EquipmentSlot handSlot = (usedHand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(usedHand) : null; + final EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); -+ event.setCancelled(itemStack == null); ++ event.setCancelled(protectionItem == null); + this.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + // Set death protection to null as the event was cancelled. Prevent any attempt at resurrection. -+ deathProtection = null; ++ protection = null; + } else { -+ if (!itemInHand.isEmpty() && itemStack != null) { // Paper - only reduce item if actual totem was found - itemInHand.shrink(1); ++ if (!itemStack.isEmpty() && protectionItem != null) { // Paper - only reduce item if actual totem was found + itemStack.shrink(1); - break; - } - } - -- if (itemStack != null) { -- if (this instanceof ServerPlayer serverPlayer) { +- if (protectionItem != null) { +- if (this instanceof ServerPlayer player) { + } + // Paper start - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled + // restore the previous behavior in that case by defaulting to vanilla's totem of undying effect -+ if (deathProtection == null) { -+ deathProtection = DeathProtection.TOTEM_OF_UNDYING; ++ if (protection == null) { ++ protection = DeathProtection.TOTEM_OF_UNDYING; + } + // Paper end - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled -+ if (itemStack != null && this instanceof final ServerPlayer serverPlayer) { -+ // CraftBukkit end - serverPlayer.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); - CriteriaTriggers.USED_TOTEM.trigger(serverPlayer, itemStack); - itemStack.causeUseVibration(this, GameEvent.ITEM_INTERACT_FINISH); -@@ -1431,6 +_,7 @@ ++ if (protectionItem != null && this instanceof final ServerPlayer player) { ++ // CraftBukkit end + player.awardStat(Stats.ITEM_USED.get(protectionItem.getItem())); + CriteriaTriggers.USED_TOTEM.trigger(player, protectionItem); + protectionItem.causeUseVibration(this, GameEvent.ITEM_INTERACT_FINISH); +@@ -1420,6 +_,7 @@ if (!this.isRemoved() && !this.dead) { - Entity entity = damageSource.getEntity(); - LivingEntity killCredit = this.getKillCredit(); + Entity sourceEntity = source.getEntity(); + LivingEntity killer = this.getKillCredit(); + /* // Paper - move down to make death event cancellable - this is the awardKillScore below - if (killCredit != null) { - killCredit.awardKillScore(this, damageSource); + if (killer != null) { + killer.awardKillScore(this, source); } -@@ -1441,68 +_,147 @@ +@@ -1430,68 +_,147 @@ this.stopUsingItem(); if (!this.level().isClientSide() && this.hasCustomName()) { @@ -818,13 +818,13 @@ - this.getCombatTracker().recheckStatus(); + // Paper - moved into if below if (this.level() instanceof ServerLevel serverLevel) { -- if (entity == null || entity.killedEntity(serverLevel, this, damageSource)) { +- if (sourceEntity == null || sourceEntity.killedEntity(serverLevel, this, source)) { + // Paper - move below into if for onKill + // Paper start -+ if (entity instanceof net.minecraft.world.entity.monster.Creeper creeper) { // Creeper has logic for drops we need capture -+ creeper.killedEntity((ServerLevel) this.level(), this, damageSource); ++ if (sourceEntity instanceof net.minecraft.world.entity.monster.Creeper creeper) { // Creeper has logic for drops we need capture ++ creeper.killedEntity((ServerLevel)this.level(), this, source); + } -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(serverLevel, damageSource); ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(serverLevel, source); + if (deathEvent == null || !deathEvent.isCancelled()) { + //if (entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent + // entityliving.awardKillScore(this, damageSource); @@ -847,20 +847,21 @@ + } + + this.getCombatTracker().recheckStatus(); -+ if (entity != null) { -+ entity.killedEntity((ServerLevel) this.level(), this, damageSource); ++ if (sourceEntity != null) { ++ sourceEntity.killedEntity((ServerLevel)this.level(), this, source); + } this.gameEvent(GameEvent.ENTITY_DIE); -- this.dropAllDeathLoot(serverLevel, damageSource); +- this.dropAllDeathLoot(serverLevel, source); +- this.createWitherRose(killer); + } else { + this.dead = false; + this.setHealth((float) deathEvent.getReviveHealth()); -+ if (entity instanceof net.minecraft.world.entity.monster.Creeper creeper && creeper.droppedSkulls) { // Creeper has logic for drops skull and need revert that flag ++ if (sourceEntity instanceof net.minecraft.world.entity.monster.Creeper creeper && creeper.droppedSkulls) { // Creeper has logic for drops skull and need revert that flag + creeper.droppedSkulls = false; + } + } + // Paper end - this.createWitherRose(killCredit); ++ this.createWitherRose(killer); } + // Paper start @@ -874,18 +875,18 @@ } } - protected void createWitherRose(@Nullable LivingEntity entitySource) { + protected void createWitherRose(final @Nullable LivingEntity killer) { if (this.level() instanceof ServerLevel serverLevel) { boolean var6 = false; -- if (entitySource instanceof WitherBoss) { -+ if (this.dead && entitySource instanceof WitherBoss) { // Paper +- if (killer instanceof WitherBoss) { ++ if (this.dead && killer instanceof WitherBoss) { // Paper if (serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) { - BlockPos blockPos = this.blockPosition(); - BlockState blockState = Blocks.WITHER_ROSE.defaultBlockState(); - if (this.level().getBlockState(blockPos).isAir() && blockState.canSurvive(this.level(), blockPos)) { -- this.level().setBlock(blockPos, blockState, Block.UPDATE_ALL); + BlockPos pos = this.blockPosition(); + BlockState state = Blocks.WITHER_ROSE.defaultBlockState(); + if (this.level().getBlockState(pos).isAir() && state.canSurvive(this.level(), pos)) { +- this.level().setBlock(pos, state, Block.UPDATE_ALL); - var6 = true; -+ var6 = CraftEventFactory.handleBlockFormEvent(this.level(), blockPos, blockState, Block.UPDATE_ALL, this); // CraftBukkit - call EntityBlockFormEvent for Wither Rose ++ var6 = CraftEventFactory.handleBlockFormEvent(this.level(), pos, state, Block.UPDATE_ALL, this); // CraftBukkit - call EntityBlockFormEvent for Wither Rose } } @@ -903,55 +904,55 @@ } } -- protected void dropAllDeathLoot(ServerLevel level, DamageSource damageSource) { +- protected void dropAllDeathLoot(final ServerLevel level, final DamageSource source) { + // Paper start + protected boolean clearEquipmentSlots = true; + protected Set clearedEquipmentSlots = new java.util.HashSet<>(); -+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel level, DamageSource damageSource) { ++ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(final ServerLevel level, final DamageSource source) { + // Paper end - boolean flag = this.lastHurtByPlayerMemoryTime > 0; + boolean playerKilled = this.lastHurtByPlayerMemoryTime > 0; + this.dropEquipment(level); // CraftBukkit - from below if (this.shouldDropLoot(level)) { - this.dropFromLootTable(level, damageSource, flag); + this.dropFromLootTable(level, source, playerKilled); + // Paper start + final boolean prev = this.clearEquipmentSlots; + this.clearEquipmentSlots = false; + this.clearedEquipmentSlots.clear(); + // Paper end - this.dropCustomDeathLoot(level, damageSource, flag); + this.dropCustomDeathLoot(level, source, playerKilled); + this.clearEquipmentSlots = prev; // Paper } - this.dropEquipment(level); + // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> { ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, source, this.drops, () -> { + final LivingEntity killer = this.getKillCredit(); + if (killer != null) { -+ killer.awardKillScore(this, damageSource); ++ killer.awardKillScore(this, source); + } + }); // Paper end + this.postDeathDropItems(deathEvent); // Paper + this.drops = new java.util.ArrayList<>(); + // this.dropEquipment(level); // CraftBukkit - moved up + // CraftBukkit end - this.dropExperience(level, damageSource.getEntity()); + this.dropExperience(level, source.getEntity()); + return deathEvent; // Paper } - protected void dropEquipment(ServerLevel level) { + protected void dropEquipment(final ServerLevel level) { } + protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled -- protected void dropExperience(ServerLevel level, @Nullable Entity entity) { -+ public int getExpReward(ServerLevel level, @Nullable Entity entity) { // CraftBukkit +- protected void dropExperience(final ServerLevel level, final @Nullable Entity killer) { ++ public int getExpReward(final ServerLevel level, final @Nullable Entity killer) { // CraftBukkit if (!this.wasExperienceConsumed() && ( this.isAlwaysExperienceDropper() || this.lastHurtByPlayerMemoryTime > 0 && this.shouldDropExperience() && level.getGameRules().get(GameRules.MOB_DROPS) )) { -- ExperienceOrb.award(level, this.position(), this.getExperienceReward(level, entity)); +- ExperienceOrb.award(level, this.position(), this.getExperienceReward(level, killer)); - } -+ return this.getExperienceReward(level, entity); // CraftBukkit ++ return this.getExperienceReward(level, killer); // CraftBukkit + } + return 0; // CraftBukkit + } @@ -965,37 +966,37 @@ + // CraftBukkit end } - protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { -@@ -1606,9 +_,14 @@ + protected void dropCustomDeathLoot(final ServerLevel level, final DamageSource source, final boolean killedByPlayer) { +@@ -1603,9 +_,14 @@ } - public void knockback(double strength, double x, double z) { + public void knockback(double power, double xd, double zd) { + // CraftBukkit start - EntityKnockbackEvent -+ this.knockback(strength, x, z, null, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.UNKNOWN); // Paper - knockback events ++ this.knockback(power, xd, zd, null, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.UNKNOWN); // Paper - knockback events + } + -+ public void knockback(double strength, double x, double z, @Nullable Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause eventCause) { // Paper - knockback events - strength *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); -- if (!(strength <= 0.0)) { ++ public void knockback(double power, double xd, double zd, @Nullable Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause eventCause) { // Paper - knockback events + power *= 1.0 - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); +- if (!(power <= 0.0)) { - this.needsSync = true; -+ if (true || !(strength <= 0.0)) { // CraftBukkit - Call event even when force is 0 ++ if (true || !(power <= 0.0)) { // CraftBukkit - Call event even when force is 0 + // this.needsSync = true; // CraftBukkit - Move down Vec3 deltaMovement = this.getDeltaMovement(); - while (x * x + z * z < 1.0E-5F) { -@@ -1617,11 +_,22 @@ + while (xd * xd + zd * zd < 1.0E-5F) { +@@ -1614,11 +_,22 @@ } - Vec3 vec3 = new Vec3(x, 0.0, z).normalize().scale(strength); + Vec3 deltaVector = new Vec3(xd, 0.0, zd).normalize().scale(power); - this.setDeltaMovement( + // Paper start - knockback events + Vec3 finalVelocity = new Vec3( - deltaMovement.x / 2.0 - vec3.x, - this.onGround() ? Math.min(0.4, deltaMovement.y / 2.0 + strength) : deltaMovement.y, - deltaMovement.z / 2.0 - vec3.z + deltaMovement.x / 2.0 - deltaVector.x, + this.onGround() ? Math.min(0.4, deltaMovement.y / 2.0 + power) : deltaMovement.y, + deltaMovement.z / 2.0 - deltaVector.z ); + Vec3 diff = finalVelocity.subtract(deltaMovement); -+ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, attacker, eventCause, strength, diff); ++ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity)this.getBukkitEntity(), attacker, attacker, eventCause, power, diff); + // Paper end - knockback events + if (event.isCancelled()) { + return; @@ -1007,7 +1008,7 @@ } } -@@ -1712,7 +_,7 @@ +@@ -1709,7 +_,7 @@ @Override public boolean isAlive() { @@ -1015,83 +1016,84 @@ + return !this.isRemoved() && this.getHealth() > 0.0F && !this.dead; // Paper - Check this.dead } - public boolean isLookingAtMe(LivingEntity entity, double tolerance, boolean scaleByDistance, boolean visual, double... yValues) { -@@ -1746,9 +_,14 @@ - boolean flag = super.causeFallDamage(fallDistance, damageMultiplier, damageSource); - int i = this.calculateFallDamage(fallDistance, damageMultiplier); - if (i > 0) { + public boolean isLookingAtMe( +@@ -1764,10 +_,15 @@ + boolean damaged = super.causeFallDamage(effectiveFallDistance, damageModifier, damageSource); + int dmg = this.calculateFallDamage(effectiveFallDistance, damageModifier); + if (dmg > 0) { + // CraftBukkit start -+ if (!this.hurtServer((ServerLevel) this.level(), damageSource, (float) i)) { ++ if (!this.hurtServer((ServerLevel)this.level(), damageSource, (float)dmg)) { + return true; + } + // CraftBukkit end - this.playSound(this.getFallDamageSound(i), 1.0F, 1.0F); + this.resetCurrentImpulseContext(); + this.playSound(this.getFallDamageSound(dmg), 1.0F, 1.0F); this.playBlockFallSound(); -- this.hurt(damageSource, i); -+ // this.hurt(damageSource, i); // CraftBukkit - moved up +- this.hurt(damageSource, dmg); ++ // this.hurt(damageSource, dmg); // CraftBukkit - moved up return true; } else { - return flag; -@@ -1813,7 +_,7 @@ + return damaged; +@@ -1865,7 +_,7 @@ - protected float getDamageAfterArmorAbsorb(DamageSource damageSource, float damageAmount) { + protected float getDamageAfterArmorAbsorb(final DamageSource damageSource, float damage) { if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) { -- this.hurtArmor(damageSource, damageAmount); -+ // this.hurtArmor(damageSource, damageAmount); // CraftBukkit - actuallyHurt(DamageSource, float, EntityDamageEvent) for damage handling - damageAmount = CombatRules.getDamageAfterAbsorb( - this, damageAmount, damageSource, this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS) +- this.hurtArmor(damageSource, damage); ++ // this.hurtArmor(damageSource, damage); // CraftBukkit - actuallyHurt(DamageSource, float, EntityDamageEvent) for damage handling + damage = CombatRules.getDamageAfterAbsorb( + this, damage, damageSource, this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS) ); -@@ -1826,7 +_,8 @@ +@@ -1878,7 +_,8 @@ if (damageSource.is(DamageTypeTags.BYPASSES_EFFECTS)) { - return damageAmount; + return damage; } else { - if (this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { + // CraftBukkit - Moved to handleEntityDamage(DamageSource, float) + if (false && this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { - int i = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; - int i1 = 25 - i; - float f = damageAmount * i1; -@@ -1863,24 +_,201 @@ + int absorbValue = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; + int absorb = 25 - absorbValue; + float v = damage * absorb; +@@ -1915,24 +_,194 @@ } } -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, float dmg) { + // CraftBukkit start -+ private EntityDamageEvent handleEntityDamage(final DamageSource damagesource, float amount, final float invulnerabilityRelatedLastDamage) { // Paper - fix invulnerability reduction in EntityDamageEvent -+ float originalDamage = amount; ++ private EntityDamageEvent handleEntityDamage(final DamageSource damagesource, float damage, final float invulnerabilityRelatedLastDamage) { // Paper - fix invulnerability reduction in EntityDamageEvent ++ float originalDamage = damage; + // Paper start - fix invulnerability reduction in EntityDamageEvent + final com.google.common.base.Function invulnerabilityReductionEquation = mod -> { -+ if (invulnerabilityRelatedLastDamage == 0) return 0D; // no last damage, no reduction ++ if (invulnerabilityRelatedLastDamage == 0) return 0.0; // no last damage, no reduction + // last damage existed, this means the reduction *technically* is (new damage - last damage). + // If the event damage was changed to something less than invul damage, hard lock it at 0. + // + // Cast the passed in double down to a float as double -> float -> double is lossy. -+ // If last damage is a (float) 3.2D (since the events use doubles), we cannot compare -+ // the new damage value of this damage instance by upcasting it again to a double as 3.2D != (double) (float) 3.2D. -+ if (mod.floatValue() < invulnerabilityRelatedLastDamage) return 0D; ++ // If last damage is a (float) 3.2 (since the events use doubles), we cannot compare ++ // the new damage value of this damage instance by upcasting it again to a double as 3.2 != (double) (float) 3.2. ++ if (mod.floatValue() < invulnerabilityRelatedLastDamage) return 0.0; + return (double) -invulnerabilityRelatedLastDamage; + }; -+ final float originalInvulnerabilityReduction = invulnerabilityReductionEquation.apply((double) amount).floatValue(); -+ amount += originalInvulnerabilityReduction; ++ final float originalInvulnerabilityReduction = invulnerabilityReductionEquation.apply((double) damage).floatValue(); ++ damage += originalInvulnerabilityReduction; + // Paper end - fix invulnerability reduction in EntityDamageEvent + + com.google.common.base.Function freezing = mod -> { -+ if (damagesource.is(net.minecraft.tags.DamageTypeTags.IS_FREEZING) && LivingEntity.this.getType().is(net.minecraft.tags.EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -+ return -(mod - (mod * 5.0F)); ++ if (damagesource.is(net.minecraft.tags.DamageTypeTags.IS_FREEZING) && LivingEntity.this.is(net.minecraft.tags.EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { ++ return -(mod - mod * 5.0F); + } + return -0.0; + }; -+ float freezingModifier = freezing.apply((double) amount).floatValue(); -+ amount += freezingModifier; ++ float freezingModifier = freezing.apply((double) damage).floatValue(); ++ damage += freezingModifier; + + com.google.common.base.Function hardHat = mod -> { + if (damagesource.is(net.minecraft.tags.DamageTypeTags.DAMAGES_HELMET) && !LivingEntity.this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { -+ return -(mod - (mod * 0.75F)); ++ return -(mod - mod * 0.75F); + } + return -0.0; + }; -+ float hardHatModifier = hardHat.apply((double) amount).floatValue(); -+ amount += hardHatModifier; ++ float hardHatModifier = hardHat.apply((double) damage).floatValue(); ++ damage += hardHatModifier; + + com.google.common.base.Function blocking = mod -> { + if (!LivingEntity.this.canBlockAttack(damagesource, mod.floatValue())) { @@ -1099,38 +1101,32 @@ + } + return (double) -LivingEntity.this.resolveBlockedDamage(damagesource, mod.floatValue()); + }; -+ float blockingModifier = blocking.apply((double) amount).floatValue(); -+ amount += blockingModifier; ++ float blockingModifier = blocking.apply((double) damage).floatValue(); ++ damage += blockingModifier; + -+ com.google.common.base.Function armor = mod -> { -+ return -(mod - LivingEntity.this.getDamageAfterArmorAbsorb(damagesource, mod.floatValue())); -+ }; -+ float armorModifier = armor.apply((double) amount).floatValue(); -+ amount += armorModifier; ++ com.google.common.base.Function armor = mod -> -(mod - LivingEntity.this.getDamageAfterArmorAbsorb(damagesource, mod.floatValue())); ++ float armorModifier = armor.apply((double) damage).floatValue(); ++ damage += armorModifier; + + com.google.common.base.Function resistance = mod -> { + if (!damagesource.is(net.minecraft.tags.DamageTypeTags.BYPASSES_EFFECTS) && LivingEntity.this.hasEffect(net.minecraft.world.effect.MobEffects.RESISTANCE) && !damagesource.is(net.minecraft.tags.DamageTypeTags.BYPASSES_RESISTANCE)) { -+ int i = (LivingEntity.this.getEffect(net.minecraft.world.effect.MobEffects.RESISTANCE).getAmplifier() + 1) * 5; -+ int j = 25 - i; -+ float f1 = mod.floatValue() * (float) j; ++ int absorbValue = (LivingEntity.this.getEffect(net.minecraft.world.effect.MobEffects.RESISTANCE).getAmplifier() + 1) * 5; ++ int absorb = 25 - absorbValue; ++ float v = mod.floatValue() * (float) absorb; + -+ return -(mod - Math.max(f1 / 25.0F, 0.0F)); ++ return -(mod - Math.max(v / 25.0F, 0.0F)); + } + return -0.0; + }; -+ float resistanceModifier = resistance.apply((double) amount).floatValue(); -+ amount += resistanceModifier; ++ float resistanceModifier = resistance.apply((double) damage).floatValue(); ++ damage += resistanceModifier; + -+ com.google.common.base.Function magic = mod -> { -+ return -(mod - net.minecraft.world.entity.LivingEntity.this.getDamageAfterMagicAbsorb(damagesource, mod.floatValue())); -+ }; -+ float magicModifier = magic.apply((double) amount).floatValue(); -+ amount += magicModifier; ++ com.google.common.base.Function magic = mod -> -(mod - net.minecraft.world.entity.LivingEntity.this.getDamageAfterMagicAbsorb(damagesource, mod.floatValue())); ++ float magicModifier = magic.apply((double) damage).floatValue(); ++ damage += magicModifier; + -+ com.google.common.base.Function absorption = mod -> { -+ return -(Math.max(mod - Math.max(mod - net.minecraft.world.entity.LivingEntity.this.getAbsorptionAmount(), 0.0F), 0.0F)); -+ }; -+ float absorptionModifier = absorption.apply((double) amount).floatValue(); ++ com.google.common.base.Function absorption = mod -> -(Math.max(mod - Math.max(mod - net.minecraft.world.entity.LivingEntity.this.getAbsorptionAmount(), 0.0F), 0.0F)); ++ float absorptionModifier = absorption.apply((double) damage).floatValue(); + + // Paper start - fix invulnerability reduction in EntityDamageEvent + return CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, freezingModifier, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, freezing, hardHat, blocking, armor, resistance, magic, absorption, (damageModifierDoubleMap, damageModifierFunctionMap) -> { @@ -1140,116 +1136,115 @@ + // Paper end - fix invulnerability reduction in EntityDamageEvent + } + -+ protected boolean actuallyHurt(ServerLevel level, final DamageSource damageSource, float amount, final EntityDamageEvent event) { // void -> boolean, add final - if (!this.isInvulnerableTo(level, damageSource)) { -- amount = this.getDamageAfterArmorAbsorb(damageSource, amount); -- amount = this.getDamageAfterMagicAbsorb(damageSource, amount); -- float var10 = Math.max(amount - this.getAbsorptionAmount(), 0.0F); -- this.setAbsorptionAmount(this.getAbsorptionAmount() - (amount - var10)); -- float f1 = amount - var10; ++ protected boolean actuallyHurt(ServerLevel level, final DamageSource source, float dmg, final EntityDamageEvent event) { // void -> boolean, add final + if (!this.isInvulnerableTo(level, source)) { +- dmg = this.getDamageAfterArmorAbsorb(source, dmg); +- dmg = this.getDamageAfterMagicAbsorb(source, dmg); +- float var10 = Math.max(dmg - this.getAbsorptionAmount(), 0.0F); +- this.setAbsorptionAmount(this.getAbsorptionAmount() - (dmg - var10)); +- float absorbedDamage = dmg - var10; + if (event.isCancelled()) { + return false; + } + -+ if (damageSource.getEntity() instanceof net.minecraft.world.entity.player.Player) { ++ if (source.getEntity() instanceof net.minecraft.world.entity.player.Player) { + // Paper start - PlayerAttackEntityCooldownResetEvent + //((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetOnlyAttackStrengthTicker(); // Moved from Player in order to make the cooldown reset get called after the damage event is fired -+ if (damageSource.getEntity() instanceof ServerPlayer) { -+ ServerPlayer player = (ServerPlayer) damageSource.getEntity(); ++ if (source.getEntity() instanceof ServerPlayer player) { + if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) { + player.resetOnlyAttackStrengthTicker(); + } + } else { -+ ((net.minecraft.world.entity.player.Player) damageSource.getEntity()).resetOnlyAttackStrengthTicker(); ++ ((net.minecraft.world.entity.player.Player)source.getEntity()).resetOnlyAttackStrengthTicker(); + } + // Paper end - PlayerAttackEntityCooldownResetEvent + } + + // Resistance + if (event.getDamage(DamageModifier.RESISTANCE) < 0) { -+ float f3 = (float) -event.getDamage(DamageModifier.RESISTANCE); -+ if (f3 > 0.0F && f3 < 3.4028235E37F) { ++ float damageResisted = (float)-event.getDamage(DamageModifier.RESISTANCE); ++ if (damageResisted > 0.0F && damageResisted < 3.4028235E37F) { + if (this instanceof ServerPlayer) { -+ ((ServerPlayer) this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f3 * 10.0F)); -+ } else if (damageSource.getEntity() instanceof ServerPlayer) { -+ ((ServerPlayer) damageSource.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(f3 * 10.0F)); ++ ((ServerPlayer)this).awardStat(Stats.DAMAGE_RESISTED, Math.round(damageResisted * 10.0F)); ++ } else if (source.getEntity() instanceof ServerPlayer) { ++ ((ServerPlayer)source.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(damageResisted * 10.0F)); + } + } + } + + // Apply damage to helmet -+ if (damageSource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { -+ float helmetDamage = (float) event.getDamage(); -+ helmetDamage += (float) event.getDamage(DamageModifier.INVULNERABILITY_REDUCTION); -+ helmetDamage += (float) event.getDamage(DamageModifier.BLOCKING); -+ helmetDamage += (float) event.getDamage(DamageModifier.FREEZING); -+ this.hurtHelmet(damageSource, helmetDamage); ++ if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { ++ float helmetDamage = (float)event.getDamage(); ++ helmetDamage += (float)event.getDamage(DamageModifier.INVULNERABILITY_REDUCTION); ++ helmetDamage += (float)event.getDamage(DamageModifier.BLOCKING); ++ helmetDamage += (float)event.getDamage(DamageModifier.FREEZING); ++ this.hurtHelmet(source, helmetDamage); + } + + // Apply damage to armor -+ if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) { -+ float armorDamage = (float) event.getDamage(); -+ armorDamage += (float) event.getDamage(DamageModifier.INVULNERABILITY_REDUCTION); -+ armorDamage += (float) event.getDamage(DamageModifier.BLOCKING); -+ armorDamage += (float) event.getDamage(DamageModifier.FREEZING); -+ armorDamage += (float) event.getDamage(DamageModifier.HARD_HAT); -+ this.hurtArmor(damageSource, armorDamage); ++ if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { ++ float armorDamage = (float)event.getDamage(); ++ armorDamage += (float)event.getDamage(DamageModifier.INVULNERABILITY_REDUCTION); ++ armorDamage += (float)event.getDamage(DamageModifier.BLOCKING); ++ armorDamage += (float)event.getDamage(DamageModifier.FREEZING); ++ armorDamage += (float)event.getDamage(DamageModifier.HARD_HAT); ++ this.hurtArmor(source, armorDamage); + } + + // Apply blocking code + if (event.getDamage(DamageModifier.BLOCKING) < 0) { -+ this.blockingItemEffects(level, damageSource, (float) -event.getDamage(DamageModifier.BLOCKING)); ++ this.blockingItemEffects(level, source, (float)-event.getDamage(DamageModifier.BLOCKING)); + } + + boolean human = this instanceof net.minecraft.world.entity.player.Player; -+ float originalDamage = (float) event.getDamage(); -+ float absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION); ++ float originalDamage = (float)event.getDamage(); ++ float absorptionModifier = (float)-event.getDamage(DamageModifier.ABSORPTION); + this.setAbsorptionAmount(Math.max(this.getAbsorptionAmount() - absorptionModifier, 0.0F)); -+ float f1 = absorptionModifier; ++ float absorbedDamage = absorptionModifier; + -+ if (f1 > 0.0F && f1 < 3.4028235E37F && this instanceof Player player) { -+ player.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f1 * 10.0F)); ++ if (absorbedDamage > 0.0F && absorbedDamage < 3.4028235E37F && this instanceof Player player) { ++ player.awardStat(Stats.DAMAGE_ABSORBED, Math.round(absorbedDamage * 10.0F)); + } + // CraftBukkit end - if (f1 > 0.0F && f1 < 3.4028235E37F && damageSource.getEntity() instanceof ServerPlayer serverPlayer) { - serverPlayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f1 * 10.0F)); + if (absorbedDamage > 0.0F && absorbedDamage < 3.4028235E37F && source.getEntity() instanceof ServerPlayer serverPlayer) { + serverPlayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(absorbedDamage * 10.0F)); } - if (var10 != 0.0F) { -- this.getCombatTracker().recordDamage(damageSource, var10); +- this.getCombatTracker().recordDamage(source, var10); - this.setHealth(this.getHealth() - var10); - this.setAbsorptionAmount(this.getAbsorptionAmount() - var10); + // CraftBukkit start -+ if (amount > 0 || !human) { ++ if (dmg > 0 || !human) { + if (human) { + // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. -+ ((net.minecraft.world.entity.player.Player) this).causeFoodExhaustion(damageSource.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent -+ if (amount < 3.4028235E37F) { -+ ((net.minecraft.world.entity.player.Player) this).awardStat(Stats.DAMAGE_TAKEN, Math.round(amount * 10.0F)); ++ ((net.minecraft.world.entity.player.Player)this).causeFoodExhaustion(source.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent ++ if (dmg < 3.4028235E37F) { ++ ((net.minecraft.world.entity.player.Player)this).awardStat(Stats.DAMAGE_TAKEN, Math.round(dmg * 10.0F)); + } + } + // CraftBukkit end -+ this.getCombatTracker().recordDamage(damageSource, amount); -+ this.setHealth(this.getHealth() - amount); ++ this.getCombatTracker().recordDamage(source, dmg); ++ this.setHealth(this.getHealth() - dmg); + // CraftBukkit start + if (!human) { -+ this.setAbsorptionAmount(this.getAbsorptionAmount() - amount); ++ this.setAbsorptionAmount(this.getAbsorptionAmount() - dmg); + } this.gameEvent(GameEvent.ENTITY_DAMAGE); + return true; + } else { + // Duplicate triggers if blocking + if (event.getDamage(DamageModifier.BLOCKING) < 0) { -+ if (this instanceof ServerPlayer) { -+ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damageSource, originalDamage, amount, true); // Paper - fix taken/dealt param order -+ f1 = (float) -event.getDamage(DamageModifier.BLOCKING); -+ if (f1 > 0.0F && f1 < 3.4028235E37F) { -+ ((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(originalDamage * 10.0F)); ++ if (this instanceof ServerPlayer serverPlayer) { ++ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger(serverPlayer, source, originalDamage, dmg, true); // Paper - fix taken/dealt param order ++ float damageBlocked = (float)-event.getDamage(DamageModifier.BLOCKING); ++ if (damageBlocked > 0.0F && damageBlocked < 3.4028235E37F) { ++ serverPlayer.awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(damageBlocked * 10.0F)); + } + } + -+ if (damageSource.getEntity() instanceof ServerPlayer) { -+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damageSource.getEntity(), this, damageSource, originalDamage, amount, true); // Paper - fix taken/dealt param order ++ if (source.getEntity() instanceof ServerPlayer) { ++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer)source.getEntity(), this, source, originalDamage, dmg, true); // Paper - fix taken/dealt param order + } + + return !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipVanillaDamageTickWhenShieldBlocked; // Paper - this should always return true, however expose an unsupported setting to flip this to false to enable "shield stunning". @@ -1263,16 +1258,16 @@ } public CombatTracker getCombatTracker() { -@@ -1908,7 +_,17 @@ +@@ -1960,7 +_,17 @@ } - public final void setArrowCount(int count) { + public final void setArrowCount(final int count) { - this.entityData.set(DATA_ARROW_COUNT_ID, count); + // CraftBukkit start + this.setArrowCount(count, false); + } + -+ public final void setArrowCount(int count, boolean reset) { ++ public final void setArrowCount(final int count, final boolean reset) { + org.bukkit.event.entity.ArrowBodyCountChangeEvent event = CraftEventFactory.callArrowBodyCountChangeEvent(this, this.getArrowCount(), count, reset); + if (event.isCancelled()) { + return; @@ -1282,16 +1277,16 @@ } public final int getStingerCount() { -@@ -1955,7 +_,7 @@ +@@ -2010,7 +_,7 @@ @Override - public void handleDamageEvent(DamageSource damageSource) { + public void handleDamageEvent(final DamageSource source) { this.walkAnimation.setSpeed(1.5F); - this.invulnerableTime = 20; + this.invulnerableTime = this.invulnerableDuration; // Paper - configurable invulnerable duration this.hurtDuration = 10; this.hurtTime = this.hurtDuration; - SoundEvent hurtSound = this.getHurtSound(damageSource); -@@ -2084,7 +_,7 @@ + SoundEvent hurtSound = this.getHurtSound(source); +@@ -2139,7 +_,7 @@ @Override protected void onBelowWorld() { @@ -1300,25 +1295,22 @@ } protected void updateSwingTime() { -@@ -2187,8 +_,15 @@ +@@ -2246,7 +_,13 @@ } - public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -- this.onEquipItem(slot, this.equipment.set(slot, stack), stack); -- } -+ // Paper start -+ this.setItemSlot(slot, stack, false); -+ } -+ // CraftBukkit start -+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { -+ // Paper end -+ this.onEquipItem(slot, this.equipment.set(slot, stack), stack, silent); + public void setItemSlot(final EquipmentSlot slot, final ItemStack itemStack) { +- this.onEquipItem(slot, this.equipment.set(slot, itemStack), itemStack); ++ // Paper start ++ this.setItemSlot(slot, itemStack, false); + } + ++ public void setItemSlot(final EquipmentSlot slot, final ItemStack itemStack, final boolean silent) { ++ this.onEquipItem(slot, this.equipment.set(slot, itemStack), itemStack, silent); ++ // Paper end + } public float getArmorCoverPercentage() { - int i = 0; -@@ -2280,14 +_,27 @@ +@@ -2339,14 +_,27 @@ return this.hasEffect(MobEffects.JUMP_BOOST) ? 0.1F * (this.getEffect(MobEffects.JUMP_BOOST).getAmplifier() + 1.0F) : 0.0F; } @@ -1327,7 +1319,7 @@ public void jumpFromGround() { float jumpPower = this.getJumpPower(); if (!(jumpPower <= 1.0E-5F)) { - Vec3 deltaMovement = this.getDeltaMovement(); + Vec3 movement = this.getDeltaMovement(); + // Paper start - Prevent excessive velocity through repeated crits + long time = System.nanoTime(); + boolean canCrit = true; @@ -1339,14 +1331,14 @@ + } + } + // Paper end - Prevent excessive velocity through repeated crits - this.setDeltaMovement(deltaMovement.x, Math.max((double)jumpPower, deltaMovement.y), deltaMovement.z); + this.setDeltaMovement(movement.x, Math.max((double)jumpPower, movement.y), movement.z); if (this.isSprinting()) { - float f = this.getYRot() * (float) (Math.PI / 180.0); + float angle = this.getYRot() * (float) (Math.PI / 180.0); + if (canCrit) // Paper - Prevent excessive velocity through repeated crits - this.addDeltaMovement(new Vec3(-Mth.sin(f) * 0.2, 0.0, Mth.cos(f) * 0.2)); + this.addDeltaMovement(new Vec3(-Mth.sin(angle) * 0.2, 0.0, Mth.cos(angle) * 0.2)); } -@@ -2470,8 +_,10 @@ +@@ -2533,8 +_,10 @@ } public void stopFallFlying() { @@ -1356,19 +1348,19 @@ + } // Paper } - private Vec3 updateFallFlyingMovement(Vec3 deltaMovement) { -@@ -2615,7 +_,7 @@ + private Vec3 updateFallFlyingMovement(Vec3 movement) { +@@ -2678,7 +_,7 @@ - public void causeExtraKnockback(Entity target, float strength, Vec3 currentMovement) { - if (strength > 0.0F && target instanceof LivingEntity livingEntity) { -- livingEntity.knockback(strength, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0))); -+ livingEntity.knockback(strength, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - knockback events + public void causeExtraKnockback(final Entity target, final float knockback, final Vec3 oldMovement) { + if (knockback > 0.0F && target instanceof LivingEntity livingTarget) { +- livingTarget.knockback(knockback, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0))); ++ livingTarget.knockback(knockback, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - knockback events this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); } } -@@ -2691,37 +_,15 @@ - profilerFiller.pop(); - profilerFiller.push("rangeChecks"); +@@ -2754,37 +_,15 @@ + profiler.pop(); + profiler.push("rangeChecks"); - while (this.getYRot() - this.yRotO < -180.0F) { - this.yRotO -= 360.0F; @@ -1411,12 +1403,12 @@ + this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; + // Paper end - stop large pitch and yaw changes from crashing the server - profilerFiller.pop(); + profiler.pop(); if (this.isFallFlying()) { -@@ -2806,16 +_,39 @@ +@@ -2879,16 +_,39 @@ private @Nullable Map collectEquipmentChanges() { - Map map = null; + Map changedItems = null; + // Paper start - EntityEquipmentChangedEvent + record EquipmentChangeImpl(org.bukkit.inventory.ItemStack oldItem, org.bukkit.inventory.ItemStack newItem) implements io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange { + @Override @@ -1432,28 +1424,28 @@ + Map equipmentChanges = null; + // Paper end - EntityEquipmentChangedEvent - for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) { - ItemStack itemStack = this.lastEquipmentItems.get(equipmentSlot); - ItemStack itemBySlot = this.getItemBySlot(equipmentSlot); - if (this.equipmentHasChanged(itemStack, itemBySlot)) { + for (EquipmentSlot slot : EquipmentSlot.VALUES) { + ItemStack previous = this.lastEquipmentItems.get(slot); + ItemStack current = this.getItemBySlot(slot); + if (this.equipmentHasChanged(previous, current)) { + // Paper start - EntityEquipmentChangedEvent, PlayerArmorChangeEvent -+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemStack); -+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemBySlot); -+ if (this instanceof ServerPlayer && equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) { -+ new com.destroystokyo.paper.event.player.PlayerArmorChangeEvent((org.bukkit.entity.Player) this.getBukkitEntity(), com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType.valueOf(equipmentSlot.name()), oldItem, newItem).callEvent(); ++ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(previous); ++ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(current); ++ if (this instanceof ServerPlayer && slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) { ++ new com.destroystokyo.paper.event.player.PlayerArmorChangeEvent((org.bukkit.entity.Player)this.getBukkitEntity(), com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType.valueOf(slot.name()), oldItem, newItem).callEvent(); + } + // Paper end - EntityEquipmentChangedEvent, PlayerArmorChangeEvent - if (map == null) { - map = Maps.newEnumMap(EquipmentSlot.class); + if (changedItems == null) { + changedItems = Maps.newEnumMap(EquipmentSlot.class); + equipmentChanges = Maps.newEnumMap(org.bukkit.inventory.EquipmentSlot.class); // Paper - EntityEquipmentChangedEvent } - map.put(equipmentSlot, itemBySlot); -+ equipmentChanges.put(org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(equipmentSlot), new EquipmentChangeImpl(oldItem, newItem)); // Paper - EntityEquipmentChangedEvent + changedItems.put(slot, current); ++ equipmentChanges.put(org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot), new EquipmentChangeImpl(oldItem, newItem)); // Paper - EntityEquipmentChangedEvent AttributeMap attributes = this.getAttributes(); - if (!itemStack.isEmpty()) { - this.stopLocationBasedEffects(itemStack, equipmentSlot, attributes); -@@ -2840,6 +_,8 @@ + if (!previous.isEmpty()) { + this.stopLocationBasedEffects(previous, slot, attributes); +@@ -2913,6 +_,8 @@ } } } @@ -1461,20 +1453,20 @@ + new io.papermc.paper.event.entity.EntityEquipmentChangedEvent(this.getBukkitLivingEntity(), equipmentChanges).callEvent(); // Paper - EntityEquipmentChangedEvent } - return map; -@@ -2871,7 +_,7 @@ - list.add(Pair.of(equipmentSlot, itemStack1)); - this.lastEquipmentItems.put(equipmentSlot, itemStack1); + return changedItems; +@@ -2944,7 +_,7 @@ + itemsToSend.add(Pair.of(slot, newItemToStore)); + this.lastEquipmentItems.put(slot, newItemToStore); }); -- ((ServerLevel)this.level()).getChunkSource().sendToTrackingPlayers(this, new ClientboundSetEquipmentPacket(this.getId(), list)); -+ ((ServerLevel)this.level()).getChunkSource().sendToTrackingPlayers(this, new ClientboundSetEquipmentPacket(this.getId(), list, true)); // Paper - data sanitization +- ((ServerLevel)this.level()).getChunkSource().sendToTrackingPlayers(this, new ClientboundSetEquipmentPacket(this.getId(), itemsToSend)); ++ ((ServerLevel)this.level()).getChunkSource().sendToTrackingPlayers(this, new ClientboundSetEquipmentPacket(this.getId(), itemsToSend, true)); // Paper - data sanitization } - protected void tickHeadTurn(float yBodyRot) { -@@ -2957,8 +_,10 @@ - if (!flag || this.onGround() && !(fluidHeight > fluidJumpThreshold)) { + protected void tickHeadTurn(final float yBodyRotT) { +@@ -3030,8 +_,10 @@ + if (!inWaterAndHasFluidHeight || this.onGround() && !(fluidHeight > fluidJumpThreshold)) { if (!this.isInLava() || this.onGround() && !(fluidHeight > fluidJumpThreshold)) { - if ((this.onGround() || flag && fluidHeight <= fluidJumpThreshold) && this.noJumpDelay == 0) { + if ((this.onGround() || inWaterAndHasFluidHeight && fluidHeight <= fluidJumpThreshold) && this.noJumpDelay == 0) { + if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API this.jumpFromGround(); this.noJumpDelay = 10; @@ -1482,19 +1474,19 @@ } } else { this.jumpInLiquid(FluidTags.LAVA); -@@ -2999,7 +_,7 @@ - profilerFiller.pop(); +@@ -3072,7 +_,7 @@ + profiler.pop(); if (this.level() instanceof ServerLevel serverLevel) { - profilerFiller.push("freezing"); + profiler.push("freezing"); - if (!this.isInPowderSnow || !this.canFreeze()) { + if ((!this.isInPowderSnow || !this.canFreeze()) && !this.freezeLocked) { // Paper - Freeze Tick Lock API this.setTicksFrozen(Math.max(0, this.getTicksFrozen() - 2)); } -@@ -3020,6 +_,20 @@ +@@ -3093,6 +_,20 @@ this.pushEntities(); - profilerFiller.pop(); + profiler.pop(); + // Paper start - Add EntityMoveEvent + if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { + if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { @@ -1512,7 +1504,7 @@ if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterOrRain()) { this.hurtServer(serverLevel, this.damageSources().drown(), 1.0F); } -@@ -3042,6 +_,7 @@ +@@ -3115,6 +_,7 @@ this.checkFallDistanceAccumulation(); if (!this.level().isClientSide()) { if (!this.canGlide()) { @@ -1520,7 +1512,7 @@ this.setSharedFlag(Entity.FLAG_FALL_FLYING, false); return; } -@@ -3081,10 +_,25 @@ +@@ -3151,10 +_,25 @@ } protected void pushEntities() { @@ -1534,40 +1526,40 @@ + return; + } + -+ int i = ((ServerLevel) this.level()).getGameRules().get(GameRules.MAX_ENTITY_CRAMMING); -+ if (i <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) { ++ int maxCramming = ((ServerLevel) this.level()).getGameRules().get(GameRules.MAX_ENTITY_CRAMMING); ++ if (maxCramming <= 0 && this.level().paperConfig().collisions.maxEntityCollisions <= 0) { + return; + } + // Paper end - don't run getEntities if we're not going to use its result List pushableEntities = this.level().getPushableEntities(this, this.getBoundingBox()); if (!pushableEntities.isEmpty()) { if (this.level() instanceof ServerLevel serverLevel) { -- int i = serverLevel.getGameRules().get(GameRules.MAX_ENTITY_CRAMMING); +- int maxCramming = serverLevel.getGameRules().get(GameRules.MAX_ENTITY_CRAMMING); + // Paper - don't run getEntities if we're not going to use its result; moved up - if (i > 0 && pushableEntities.size() > i - 1 && this.random.nextInt(4) == 0) { - int i1 = 0; + if (maxCramming > 0 && pushableEntities.size() > maxCramming - 1 && this.random.nextInt(4) == 0) { + int count = 0; -@@ -3100,7 +_,16 @@ +@@ -3170,7 +_,16 @@ } } + // Paper start - Cap entity collisions + this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions); - for (Entity entity1 : pushableEntities) { + for (Entity entityx : pushableEntities) { + if (this.numCollisions >= this.level().paperConfig().collisions.maxEntityCollisions) { + break; + } + -+ entity1.numCollisions++; ++ entityx.numCollisions++; + this.numCollisions++; + // Paper end - Cap entity collisions - this.doPush(entity1); + this.doPush(entityx); } } -@@ -3109,16 +_,32 @@ - protected void checkAutoSpinAttack(AABB boundingBoxBeforeSpin, AABB boundingBoxAfterSpin) { - AABB aabb = boundingBoxBeforeSpin.minmax(boundingBoxAfterSpin); - List entities = this.level().getEntities(this, aabb); +@@ -3179,16 +_,32 @@ + protected void checkAutoSpinAttack(final AABB old, final AABB current) { + AABB minmax = old.minmax(current); + List entities = this.level().getEntities(this, minmax); + int skippedAttackedEntitiesCounter = 0; // Paper - entity attempt spin attack event / hidden entities - count entities that are retroactively not part of the list if (!entities.isEmpty()) { for (Entity entity : entities) { @@ -1598,49 +1590,49 @@ this.autoSpinAttackTicks = 0; } -@@ -3141,10 +_,10 @@ +@@ -3211,10 +_,10 @@ } @Override - public void stopRiding() { -+ public void stopRiding(boolean suppressCancellation) { // Paper - Force entity dismount during teleportation - Entity vehicle = this.getVehicle(); ++ public void stopRiding(final boolean suppressCancellation) { // Paper - Force entity dismount during teleportation + Entity oldVehicle = this.getVehicle(); - super.stopRiding(); -- if (vehicle != null && vehicle != this.getVehicle() && !this.level().isClientSide()) { +- if (oldVehicle != null && oldVehicle != this.getVehicle() && !this.level().isClientSide()) { + super.stopRiding(suppressCancellation); // Paper - Force entity dismount during teleportation -+ if (vehicle != null && vehicle != this.getVehicle() && !this.level().isClientSide() && vehicle.valid) { // Paper - don't process on world gen - this.dismountVehicle(vehicle); ++ if (oldVehicle != null && oldVehicle != this.getVehicle() && !this.level().isClientSide() && oldVehicle.valid) { // Paper - don't process on world gen + this.dismountVehicle(oldVehicle); } } -@@ -3171,7 +_,7 @@ +@@ -3241,7 +_,7 @@ } - public void onItemPickup(ItemEntity itemEntity) { -- Entity owner = itemEntity.getOwner(); -+ Entity owner = EntityReference.getEntity(itemEntity.thrower, this.level()::getGlobalPlayerByUUID, Entity.class); // Paper - check global player list where appropriate - if (owner instanceof ServerPlayer) { - CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer)owner, itemEntity.getItem(), this); + public void onItemPickup(final ItemEntity entity) { +- Entity thrower = entity.getOwner(); ++ Entity thrower = EntityReference.getEntity(entity.thrower, this.level()::getGlobalPlayerByUUID, Entity.class); // Paper - check global player list where appropriate + if (thrower instanceof ServerPlayer) { + CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer)thrower, entity.getItem(), this); } -@@ -3183,7 +_,7 @@ +@@ -3253,7 +_,7 @@ && (entity instanceof ItemEntity || entity instanceof AbstractArrow || entity instanceof ExperienceOrb)) { ((ServerLevel)this.level()) .getChunkSource() -- .sendToTrackingPlayers(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), amount)); -+ .sendToTrackingPlayersAndSelf(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), amount)); // Paper - broadcast with collector as source +- .sendToTrackingPlayers(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), orgCount)); ++ .sendToTrackingPlayersAndSelf(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), orgCount)); // Paper - broadcast with collector as source } } -@@ -3197,7 +_,8 @@ +@@ -3269,7 +_,8 @@ } else { - Vec3 vec3 = new Vec3(this.getX(), this.getEyeY(), this.getZ()); - Vec3 vec31 = new Vec3(entity.getX(), y, entity.getZ()); -- return !(vec31.distanceTo(vec3) > 128.0) && this.level().clip(new ClipContext(vec3, vec31, block, fluid, this)).getType() == HitResult.Type.MISS; + Vec3 from = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + Vec3 to = new Vec3(target.getX(), eyeHeight, target.getZ()); +- return !(to.distanceTo(from) > 128.0) + // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists -+ return !(vec31.distanceToSqr(vec3) > 128.0D * 128.0D) && this.level().clip(new ClipContext(vec3, vec31, block, fluid, this)).getType() == HitResult.Type.MISS; // Paper - Perf: Use distance squared ++ return !(to.distanceToSqr(from) > Mth.square(128.0)) // Paper - Perf: Use distance squared + && this.level().clip(new ClipContext(from, to, blockCollidingContext, fluidCollidingContext, this)).getType() == HitResult.Type.MISS; } } - -@@ -3217,13 +_,27 @@ +@@ -3290,13 +_,27 @@ @Override public boolean isPickable() { @@ -1671,16 +1663,16 @@ @Override public float getYHeadRot() { -@@ -3254,7 +_,7 @@ +@@ -3327,7 +_,7 @@ } - public final void setAbsorptionAmount(float absorptionAmount) { + public final void setAbsorptionAmount(final float absorptionAmount) { - this.internalSetAbsorptionAmount(Mth.clamp(absorptionAmount, 0.0F, this.getMaxAbsorption())); + this.internalSetAbsorptionAmount(!Float.isNaN(absorptionAmount) ? Mth.clamp(absorptionAmount, 0.0F, this.getMaxAbsorption()) : 0.0F); // Paper - Check for NaN } - protected void internalSetAbsorptionAmount(float absorptionAmount) { -@@ -3281,6 +_,15 @@ + protected void internalSetAbsorptionAmount(final float absorptionAmount) { +@@ -3354,6 +_,15 @@ return (this.entityData.get(DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; } @@ -1696,43 +1688,43 @@ private void updatingUsingItem() { if (this.isUsingItem()) { if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) { -@@ -3328,7 +_,12 @@ +@@ -3401,7 +_,12 @@ - protected void updateUsingItem(ItemStack usingItem) { - usingItem.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); -- if (--this.useItemRemaining == 0 && !this.level().isClientSide() && !usingItem.useOnRelease()) { + protected void updateUsingItem(final ItemStack useItem) { + useItem.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); +- if (--this.useItemRemaining == 0 && !this.level().isClientSide() && !useItem.useOnRelease()) { + // Paper start - lag compensate eating + // we add 1 to the expected time to avoid lag compensating when we should not + final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L)); -+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !usingItem.useOnRelease()) { ++ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !useItem.useOnRelease()) { + this.useItemRemaining = 0; + // Paper end - lag compensate eating this.completeUsingItem(); } } -@@ -3354,10 +_,19 @@ +@@ -3427,10 +_,19 @@ } - public void startUsingItem(InteractionHand hand) { + public void startUsingItem(final InteractionHand hand) { + // Paper start - Prevent consuming the wrong itemstack + this.startUsingItem(hand, false); + } + -+ public void startUsingItem(InteractionHand hand, boolean forceUpdate) { ++ public void startUsingItem(final InteractionHand hand, final boolean forceUpdate) { + // Paper end - Prevent consuming the wrong itemstack - ItemStack itemInHand = this.getItemInHand(hand); -- if (!itemInHand.isEmpty() && !this.isUsingItem()) { -+ if (!itemInHand.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack - this.useItem = itemInHand; -- this.useItemRemaining = itemInHand.getUseDuration(this); + ItemStack itemStack = this.getItemInHand(hand); +- if (!itemStack.isEmpty() && !this.isUsingItem()) { ++ if ((!itemStack.isEmpty() && !this.isUsingItem()) || forceUpdate) { // Paper - Prevent consuming the wrong itemstack + this.useItem = itemStack; +- this.useItemRemaining = itemStack.getUseDuration(this); + // Paper start - lag compensate eating -+ this.useItemRemaining = this.totalEatTimeTicks = itemInHand.getUseDuration(this); ++ this.useItemRemaining = this.totalEatTimeTicks = itemStack.getUseDuration(this); + this.eatStartTime = System.nanoTime(); + // Paper end - lag compensate eating if (!this.level().isClientSide()) { this.setLivingEntityFlag(LIVING_ENTITY_FLAG_IS_USING, true); this.setLivingEntityFlag(LIVING_ENTITY_FLAG_OFF_HAND, hand == InteractionHand.OFF_HAND); -@@ -3384,7 +_,10 @@ +@@ -3457,7 +_,10 @@ } } else if (!this.isUsingItem() && !this.useItem.isEmpty()) { this.useItem = ItemStack.EMPTY; @@ -1744,19 +1736,19 @@ } } } -@@ -3423,9 +_,41 @@ +@@ -3500,9 +_,41 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { -- ItemStack itemStack = this.useItem.finishUsingItem(this.level(), this); +- ItemStack result = this.useItem.finishUsingItem(this.level(), this); + this.startUsingItem(this.getUsedItemHand(), true); // Paper - Prevent consuming the wrong itemstack + // CraftBukkit start - fire PlayerItemConsumeEvent -+ ItemStack itemStack; ++ ItemStack result; + org.bukkit.event.player.PlayerItemConsumeEvent event = null; // Paper + if (this instanceof ServerPlayer serverPlayer) { + org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem); -+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(usedItemHand); -+ event = new org.bukkit.event.player.PlayerItemConsumeEvent((org.bukkit.entity.Player) this.getBukkitEntity(), craftItem, hand); // Paper ++ org.bukkit.inventory.EquipmentSlot handSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); ++ event = new org.bukkit.event.player.PlayerItemConsumeEvent((org.bukkit.entity.Player)this.getBukkitEntity(), craftItem, handSlot); // Paper + this.level().getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { @@ -1764,38 +1756,38 @@ + if (consumable != null) { + consumable.cancelUsingItem(serverPlayer, this.useItem); + } -+ serverPlayer.containerMenu.forceHeldSlot(usedItemHand); ++ serverPlayer.containerMenu.forceHeldSlot(hand); + serverPlayer.getBukkitEntity().updateScaledHealth(); + this.stopUsingItem(); // Paper - event is using an item, clear active item to reset its use + return; + } + -+ itemStack = (craftItem.equals(event.getItem())) ? this.useItem.finishUsingItem(this.level(), this) : CraftItemStack.asNMSCopy(event.getItem()).finishUsingItem(this.level(), this); ++ result = (craftItem.equals(event.getItem())) ? this.useItem.finishUsingItem(this.level(), this) : CraftItemStack.asNMSCopy(event.getItem()).finishUsingItem(this.level(), this); + } else { -+ itemStack = this.useItem.finishUsingItem(this.level(), this); ++ result = this.useItem.finishUsingItem(this.level(), this); + } + // Paper start - save the default replacement item and change it if necessary -+ final ItemStack defaultReplacement = itemStack; ++ final ItemStack defaultReplacement = result; + if (event != null && event.getReplacement() != null) { -+ itemStack = CraftItemStack.asNMSCopy(event.getReplacement()); ++ result = CraftItemStack.asNMSCopy(event.getReplacement()); + } + // Paper end + // CraftBukkit end - if (itemStack != this.useItem) { - this.setItemInHand(usedItemHand, itemStack); -+ if (event != null && event.getReplacement() != null && this instanceof final ServerPlayer player) player.containerMenu.forceHeldSlot(usedItemHand); // Paper - Fix inventory desync; Paper#13253 + if (result != this.useItem) { + this.setItemInHand(hand, result); ++ if (event != null && event.getReplacement() != null && this instanceof final ServerPlayer player) player.containerMenu.forceHeldSlot(hand); // Paper - Fix inventory desync; Paper#13253 } this.stopUsingItem(); -@@ -3457,6 +_,7 @@ - ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand()); - if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) { - this.useItem = itemInHand; +@@ -3534,6 +_,7 @@ + ItemStack itemInUsedHand = this.getItemInHand(this.getUsedItemHand()); + if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInUsedHand, this.useItem)) { + this.useItem = itemInUsedHand; + if (this instanceof ServerPlayer) new io.papermc.paper.event.player.PlayerStopUsingItemEvent((org.bukkit.entity.Player) getBukkitEntity(), useItem.asBukkitMirror(), getTicksUsingItem()).callEvent(); // Paper - Add PlayerStopUsingItemEvent this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks()); if (this.useItem.useOnRelease()) { this.updatingUsingItem(); -@@ -3477,7 +_,10 @@ +@@ -3554,7 +_,10 @@ } this.useItem = ItemStack.EMPTY; @@ -1807,7 +1799,7 @@ } public boolean isBlocking() { -@@ -3500,6 +_,60 @@ +@@ -3577,6 +_,60 @@ } } @@ -1841,9 +1833,9 @@ + Vec3 direction = this.getLookAngle(); + Vec3 end = start.add(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance); + -+ List entityList = this.level().getEntities(this, getBoundingBox().expandTowards(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance).inflate(1.0D, 1.0D, 1.0D), EntitySelector.NO_SPECTATORS.and(Entity::isPickable)); ++ List entityList = this.level().getEntities(this, getBoundingBox().expandTowards(direction.x * maxDistance, direction.y * maxDistance, direction.z * maxDistance).inflate(1.0), EntitySelector.NO_SPECTATORS.and(Entity::isPickable)); + -+ double distance = 0.0D; ++ double distance = 0.0; + net.minecraft.world.phys.EntityHitResult result = null; + + for (Entity entity : entityList) { @@ -1854,7 +1846,7 @@ + if (rayTraceResult.isPresent()) { + Vec3 rayTrace = rayTraceResult.get(); + double distanceTo = start.distanceToSqr(rayTrace); -+ if (distanceTo < distance || distance == 0.0D) { ++ if (distanceTo < distance || distance == 0.0) { + result = new net.minecraft.world.phys.EntityHitResult(entity, rayTrace); + distance = distanceTo; + } @@ -1868,36 +1860,36 @@ public boolean isSuppressingSlidingDownLadder() { return this.isShiftKeyDown(); } -@@ -3518,6 +_,12 @@ +@@ -3595,6 +_,12 @@ } - public boolean randomTeleport(double x, double y, double z, boolean broadcastTeleport) { + public boolean randomTeleport(final double xx, final double yy, final double zz, final boolean showParticles) { + // CraftBukkit start -+ return this.randomTeleport(x, y, z, broadcastTeleport, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN).orElse(false); ++ return this.randomTeleport(xx, yy, zz, showParticles, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN).orElse(false); + } + -+ public Optional randomTeleport(double x, double y, double z, boolean broadcastTeleport, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { ++ public Optional randomTeleport(final double xx, final double yy, final double zz, final boolean showParticles, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { + // CraftBukkit end - double x1 = this.getX(); - double y1 = this.getY(); - double z1 = this.getZ(); -@@ -3540,16 +_,39 @@ + double xo = this.getX(); + double yo = this.getY(); + double zo = this.getZ(); +@@ -3617,16 +_,39 @@ } - if (flag1) { -- this.teleportTo(x, d, z); + if (landed) { +- this.teleportTo(xx, y, zz); + // CraftBukkit start - Teleport event + // first set position, to check if the place to teleport is valid -+ this.setPos(x, d, z); ++ this.setPos(xx, y, zz); if (level.noCollision(this) && !level.containsAnyLiquid(this.getBoundingBox())) { - flag = true; + ok = true; } + // now revert and call event if the teleport place is valid -+ this.setPos(x1, y1, z1); ++ this.setPos(xo, yo, zo); + -+ if (flag) { ++ if (ok) { + if (!(this instanceof ServerPlayer)) { -+ org.bukkit.event.entity.EntityTeleportEvent teleport = new org.bukkit.event.entity.EntityTeleportEvent(this.getBukkitEntity(), new Location(this.level().getWorld(), x1, y1, z1), new Location(this.level().getWorld(), x, d, z)); ++ org.bukkit.event.entity.EntityTeleportEvent teleport = new org.bukkit.event.entity.EntityTeleportEvent(this.getBukkitEntity(), new Location(this.level().getWorld(), xo, yo, zo), new Location(this.level().getWorld(), xx, y, zz)); + this.level().getCraftServer().getPluginManager().callEvent(teleport); + if (!teleport.isCancelled() && teleport.getTo() != null) { // Paper + Location to = teleport.getTo(); @@ -1907,7 +1899,7 @@ + } + } else { + // player teleport event is called in the underlining code -+ if (!((ServerPlayer) this).connection.teleport(x, d, z, this.getYRot(), this.getXRot(), cause)) { ++ if (!((ServerPlayer) this).connection.teleport(xx, y, zz, this.getYRot(), this.getXRot(), cause)) { + return Optional.empty(); + } + } @@ -1916,15 +1908,15 @@ } } - if (!flag) { -- this.teleportTo(x1, y1, z1); + if (!ok) { +- this.teleportTo(xo, yo, zo); - return false; -+ // this.teleportTo(x1, y1, z1); // CraftBukkit - already set the location back ++ // this.teleportTo(xo, yo, zo); // CraftBukkit - already set the location back + return Optional.of(false); // CraftBukkit } else { - if (broadcastTeleport) { + if (showParticles) { level.broadcastEntityEvent(this, EntityEvent.TELEPORT); -@@ -3559,7 +_,7 @@ +@@ -3636,7 +_,7 @@ pathfinderMob.getNavigation().stop(); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch index 49ab35ca45a1..fa3e3bce9f23 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -12,7 +12,7 @@ +import org.bukkit.event.entity.EntityUnleashEvent; +// CraftBukkit end + - public abstract class Mob extends LivingEntity implements EquipmentUser, Leashable, Targeting { + public abstract class Mob extends LivingEntity implements Targeting, EquipmentUser, Leashable { private static final EntityDataAccessor DATA_MOB_FLAGS_ID = SynchedEntityData.defineId(Mob.class, EntityDataSerializers.BYTE); private static final int MOB_FLAG_NO_AI = 1; @@ -127,6 +_,7 @@ @@ -30,62 +30,55 @@ + public boolean aware = true; // CraftBukkit + public net.kyori.adventure.util.TriState despawnInPeacefulOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - allow changing despawnInPeaceful - protected Mob(EntityType type, Level level) { + protected Mob(final EntityType type, final Level level) { super(type, level); -@@ -155,6 +_,12 @@ - } - } - -+ // CraftBukkit start -+ public void setPersistenceRequired(boolean persistenceRequired) { -+ this.persistenceRequired = persistenceRequired; -+ } -+ // CraftBukkit end -+ - protected void registerGoals() { - } - -@@ -232,7 +_,39 @@ +@@ -244,7 +_,44 @@ } - public void setTarget(@Nullable LivingEntity target) { + public void setTarget(final @Nullable LivingEntity target) { +- this.target = this.asValidTarget(target); + // CraftBukkit start - fire event + this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN); + } + + public boolean setTarget(@Nullable LivingEntity target, EntityTargetEvent.@Nullable TargetReason reason) { -+ if (this.getTarget() == target) { ++ LivingEntity currentTarget = this.getTargetUnchecked(); ++ if (Objects.equals(currentTarget, target)) { + return false; + } ++ LivingEntity originalTarget = target; ++ target = asValidTarget(target); + if (reason != null) { -+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && target == null) { -+ reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; ++ if (target != originalTarget) { // target got pruned in asValidTarget ++ reason = org.bukkit.craftbukkit.event.CraftEventFactory.getForgotTargetReason(this, currentTarget, true); ++ originalTarget = target; ++ } else if (reason == EntityTargetEvent.TargetReason.FORGOT_TARGET || (reason == EntityTargetEvent.TargetReason.UNKNOWN && target == null)) { // try to get a more relevant reason ++ reason = org.bukkit.craftbukkit.event.CraftEventFactory.getForgotTargetReason(this, currentTarget, false); + } + if (reason == EntityTargetEvent.TargetReason.UNKNOWN) { + this.level().getCraftServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception()); + } -+ org.bukkit.craftbukkit.entity.CraftLivingEntity ctarget = null; -+ if (target != null) { -+ ctarget = (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity(); -+ } -+ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = new org.bukkit.event.entity.EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason); -+ if (!event.callEvent()) { ++ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this, target, reason); ++ if (event.isCancelled()) { + return false; + } + + if (event.getTarget() != null) { + target = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); ++ if (target != originalTarget) { ++ target = asValidTarget(target); ++ } + } else { + target = null; + } + } - this.target = target; ++ this.target = target; + return true; + // CraftBukkit end } @Override -@@ -371,13 +_,27 @@ +@@ -383,13 +_,27 @@ if (this.isNoAi()) { output.putBoolean("NoAI", this.isNoAi()); } @@ -98,7 +91,7 @@ } @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { super.readAdditionalSaveData(input); - this.setCanPickUpLoot(input.getBooleanOr("CanPickUpLoot", false)); - this.persistenceRequired = input.getBooleanOr("PersistenceRequired", false); @@ -115,7 +108,7 @@ this.dropChances = input.read("drop_chances", DropChances.CODEC).orElse(DropChances.DEFAULT); this.readLeashData(input); this.homeRadius = input.getIntOr("home_radius", -1); -@@ -389,6 +_,13 @@ +@@ -401,6 +_,13 @@ this.lootTable = input.read("DeathLootTable", LootTable.KEY_CODEC); this.lootTableSeed = input.getLongOr("DeathLootTableSeed", 0L); this.setNoAi(input.getBooleanOr("NoAI", false)); @@ -129,67 +122,67 @@ } @Override -@@ -456,6 +_,11 @@ - && !itemEntity.getItem().isEmpty() - && !itemEntity.hasPickUpDelay() - && this.wantsToPickUp(serverLevel, itemEntity.getItem())) { +@@ -465,6 +_,11 @@ + for (ItemEntity entity : this.level() + .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(pickupReach.getX(), pickupReach.getY(), pickupReach.getZ()))) { + if (!entity.isRemoved() && !entity.getItem().isEmpty() && !entity.hasPickUpDelay() && this.wantsToPickUp(serverLevel, entity.getItem())) { + // Paper start - Item#canEntityPickup -+ if (!itemEntity.canMobPickup) { ++ if (!entity.canMobPickup) { + continue; + } + // Paper end - Item#canEntityPickup - this.pickUpItem(serverLevel, itemEntity); + this.pickUpItem(serverLevel, entity); } } -@@ -509,18 +_,24 @@ +@@ -515,18 +_,24 @@ - protected void pickUpItem(ServerLevel level, ItemEntity entity) { - ItemStack item = entity.getItem(); -- ItemStack itemStack = this.equipItemIfPossible(level, item.copy()); -+ ItemStack itemStack = this.equipItemIfPossible(level, item.copy(), entity); // CraftBukkit - add item - if (!itemStack.isEmpty()) { + protected void pickUpItem(final ServerLevel level, final ItemEntity entity) { + ItemStack itemStack = entity.getItem(); +- ItemStack equippedWithStack = this.equipItemIfPossible(level, itemStack.copy()); ++ ItemStack equippedWithStack = this.equipItemIfPossible(level, itemStack.copy(), entity); // CraftBukkit - add item + if (!equippedWithStack.isEmpty()) { this.onItemPickup(entity); - this.take(entity, itemStack.getCount()); - item.shrink(itemStack.getCount()); - if (item.isEmpty()) { + this.take(entity, equippedWithStack.getCount()); + itemStack.shrink(equippedWithStack.getCount()); + if (itemStack.isEmpty()) { - entity.discard(); + entity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } } } - public ItemStack equipItemIfPossible(ServerLevel level, ItemStack stack) { + public ItemStack equipItemIfPossible(final ServerLevel level, final ItemStack itemStack) { + // CraftBukkit start - add item -+ return this.equipItemIfPossible(level, stack, null); ++ return this.equipItemIfPossible(level, itemStack, null); + } + -+ public ItemStack equipItemIfPossible(ServerLevel level, ItemStack stack, @Nullable ItemEntity entity) { ++ public ItemStack equipItemIfPossible(final ServerLevel level, final ItemStack itemStack, final @Nullable ItemEntity entity) { + // CraftBukkit end - EquipmentSlot equipmentSlotForItem = this.getEquipmentSlotForItem(stack); - if (!this.isEquippableInSlot(stack, equipmentSlotForItem)) { + EquipmentSlot slot = this.getEquipmentSlotForItem(itemStack); + if (!this.isEquippableInSlot(itemStack, slot)) { return ItemStack.EMPTY; -@@ -533,10 +_,18 @@ - canReplaceCurrentItem = itemBySlot.isEmpty(); +@@ -539,10 +_,18 @@ + canReplace = current.isEmpty(); } -- if (canReplaceCurrentItem && this.canHoldItem(stack)) { +- if (canReplace && this.canHoldItem(itemStack)) { + // CraftBukkit start -+ boolean canPickup = canReplaceCurrentItem && this.canHoldItem(stack); ++ boolean canPickup = canReplace && this.canHoldItem(itemStack); + if (entity != null) { + canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, !canPickup).isCancelled(); + } + if (canPickup) { + // CraftBukkit end - double d = this.dropChances.byEquipment(equipmentSlotForItem); - if (!itemBySlot.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d) { + double dropChance = this.dropChances.byEquipment(slot); + if (!current.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < dropChance) { + this.forceDrops = true; // CraftBukkit - this.spawnAtLocation(level, itemBySlot); + this.spawnAtLocation(level, current); + this.forceDrops = false; // CraftBukkit } - ItemStack itemStack = equipmentSlotForItem.limit(stack); -@@ -649,25 +_,38 @@ - return this.isPassenger(); + ItemStack toEquip = slot.limit(itemStack); +@@ -651,25 +_,38 @@ + return this.isPassenger() || this.isLeashed(); } + // Paper start - allow changing despawnInPeaceful @@ -205,33 +198,32 @@ + if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { // Paper - allow changing despawnInPeaceful + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { -- Entity nearestPlayer = this.level().getNearestPlayer(this, -1.0); -+ Entity nearestPlayer = this.level().findNearbyPlayer(this, -1.0, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API - if (nearestPlayer != null) { -- double d = nearestPlayer.distanceToSqr(this); -- int despawnDistance = this.getType().getCategory().getDespawnDistance(); -- int i = despawnDistance * despawnDistance; -- if (d > i && this.removeWhenFarAway(d)) { +- Entity player = this.level().getNearestPlayer(this, -1.0); ++ Entity player = this.level().findNearbyPlayer(this, -1.0, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API + if (player != null) { +- double distSqr = player.distanceToSqr(this); +- int instantDespawnDistance = this.getType().getCategory().getDespawnDistance(); +- int despawnDistanceSqr = instantDespawnDistance * instantDespawnDistance; +- if (distSqr > despawnDistanceSqr && this.removeWhenFarAway(distSqr)) { - this.discard(); -- } + // Paper start - Configurable despawn distances + final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()); + final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape; -+ final double dy = Math.abs(nearestPlayer.getY() - this.getY()); ++ final double dy = Math.abs(player.getY() - this.getY()); + final double dySqr = Mth.square(dy); -+ final double dxSqr = Mth.square(nearestPlayer.getX() - this.getX()); -+ final double dzSqr = Mth.square(nearestPlayer.getZ() - this.getZ()); ++ final double dxSqr = Mth.square(player.getX() - this.getX()); ++ final double dzSqr = Mth.square(player.getZ() - this.getZ()); + final double distanceSquared = dxSqr + dzSqr + dySqr; + // Despawn if hard/soft limit is exceeded + if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) { + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause -+ } + } - int noDespawnDistance = this.getType().getCategory().getNoDespawnDistance(); -- int i1 = noDespawnDistance * noDespawnDistance; -- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d > i1 && this.removeWhenFarAway(d)) { +- int noDespawnDistanceSqr = noDespawnDistance * noDespawnDistance; +- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && distSqr > noDespawnDistanceSqr && this.removeWhenFarAway(distSqr)) { - this.discard(); -- } else if (d < i1) { +- } else if (distSqr < noDespawnDistanceSqr) { + if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) { + if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) { + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause @@ -241,7 +233,7 @@ this.noActionTime = 0; } } -@@ -679,6 +_,15 @@ +@@ -681,6 +_,15 @@ @Override protected final void serverAiStep() { this.noActionTime++; @@ -254,11 +246,11 @@ + return; + } + // Paper end - Allow nerfed mobs to jump and float - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("sensing"); + ProfilerFiller profiler = Profiler.get(); + profiler.push("sensing"); this.sensing.tick(); -@@ -853,14 +_,69 @@ - public boolean stillValid(Player player) { +@@ -859,14 +_,69 @@ + public boolean stillValid(final Player player) { return player.getVehicle() == Mob.this || player.isWithinEntityInteractionRange(Mob.this, 4.0); } + @@ -319,115 +311,116 @@ + // Paper end + @Override - protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { - super.dropCustomDeathLoot(level, damageSource, recentlyHit); + protected void dropCustomDeathLoot(final ServerLevel level, final DamageSource source, final boolean killedByPlayer) { + super.dropCustomDeathLoot(level, source, killedByPlayer); - for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) { -+ if (this.shouldSkipLoot(equipmentSlot)) continue; // Paper - ItemStack itemBySlot = this.getItemBySlot(equipmentSlot); - float f = this.dropChances.byEquipment(equipmentSlot); - if (f != 0.0F) { -@@ -880,7 +_,13 @@ + for (EquipmentSlot slot : EquipmentSlot.VALUES) { ++ if (this.shouldSkipLoot(slot)) continue; // Paper + ItemStack itemStack = this.getItemBySlot(slot); + float dropChance = this.dropChances.byEquipment(slot); + if (dropChance != 0.0F) { +@@ -886,7 +_,13 @@ } - this.spawnAtLocation(level, itemBySlot); + this.spawnAtLocation(level, itemStack); + if (this.clearEquipmentSlots) { // Paper - this.setItemSlot(equipmentSlot, ItemStack.EMPTY); + this.setItemSlot(slot, ItemStack.EMPTY); + // Paper start + } else { -+ this.clearedEquipmentSlots.add(equipmentSlot); ++ this.clearedEquipmentSlots.add(slot); + } + // Paper end } } } -@@ -904,7 +_,9 @@ - set.add(equipmentSlot); - } else if (this.dropChances.isPreserved(equipmentSlot)) { - this.setItemSlot(equipmentSlot, ItemStack.EMPTY); +@@ -910,7 +_,9 @@ + slotsPreventedFromDropping.add(slot); + } else if (this.dropChances.isPreserved(slot)) { + this.setItemSlot(slot, ItemStack.EMPTY); + this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.spawnAtLocation(level, itemBySlot); + this.spawnAtLocation(level, itemStack); + this.forceDrops = false; // Paper - Add missing forceDrop toggles } } } -@@ -1195,6 +_,21 @@ - public @Nullable T convertTo( - EntityType entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.AfterConversion afterConversion +@@ -1210,6 +_,22 @@ + final EntitySpawnReason spawnReason, + final ConversionParams.AfterConversion afterConversion ) { + // Paper start - entity zap event - allow cancellation of conversion post creation -+ return this.convertTo(entityType, conversionParams, spawnReason, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); ++ return this.convertTo(entityType, params, spawnReason, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + @Nullable + public T convertTo( -+ EntityType entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.AfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason ++ EntityType entityType, ConversionParams params, EntitySpawnReason spawnReason, ConversionParams.AfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason + ) { -+ return this.convertTo(entityType, conversionParams, spawnReason, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, creatureSpawnReason); ++ return this.convertTo(entityType, params, spawnReason, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, creatureSpawnReason); + } ++ + @Nullable + public T convertTo( -+ EntityType entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.CancellingAfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason ++ EntityType entityType, ConversionParams params, EntitySpawnReason spawnReason, ConversionParams.CancellingAfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason + ) { + // Paper end - entity zap event - allow cancellation of conversion post creation if (this.isRemoved()) { return null; } else { -@@ -1203,13 +_,23 @@ +@@ -1218,13 +_,23 @@ return null; } else { - conversionParams.type().convert(this, mob, conversionParams); -- afterConversion.finalizeConversion(mob); -+ if (!afterConversion.finalizeConversionOrCancel(mob)) return null; // Paper - entity zap event - return null if conversion was cancelled + params.type().convert(this, newMob, params); +- afterConversion.finalizeConversion(newMob); ++ if (!afterConversion.finalizeConversionOrCancel(newMob)) return null; // Paper - entity zap event - return null if conversion was cancelled + // CraftBukkit start + if (transformReason == null) { + // Special handling for slime split and pig lightning -+ return mob; ++ return newMob; + } + -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, mob, transformReason).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, newMob, transformReason).isCancelled()) { + return null; + } + // CraftBukkit end if (this.level() instanceof ServerLevel serverLevel) { -- serverLevel.addFreshEntity(mob); -+ serverLevel.addFreshEntity(mob, creatureSpawnReason); // CraftBukkit +- serverLevel.addFreshEntity(newMob); ++ serverLevel.addFreshEntity(newMob, creatureSpawnReason); // CraftBukkit } - if (conversionParams.type().shouldDiscardAfterConversion()) { + if (params.type().shouldDiscardAfterConversion()) { - this.discard(); + this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause } - return mob; -@@ -1220,7 +_,17 @@ + return newMob; +@@ -1235,7 +_,17 @@ public @Nullable T convertTo( - EntityType entityType, ConversionParams conversionParams, ConversionParams.AfterConversion afterConversion + final EntityType entityType, final ConversionParams params, final ConversionParams.AfterConversion afterConversion ) { -- return this.convertTo(entityType, conversionParams, EntitySpawnReason.CONVERSION, afterConversion); +- return this.convertTo(entityType, params, EntitySpawnReason.CONVERSION, afterConversion); + // Paper start - entity zap event - allow cancellation of conversion post creation -+ return this.convertTo(entityType, conversionParams, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); ++ return this.convertTo(entityType, params, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); + } + -+ public @Nullable T convertTo(EntityType entityType, ConversionParams conversionParams, ConversionParams.AfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason) { -+ return this.convertTo(entityType, conversionParams, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, creatureSpawnReason); ++ public @Nullable T convertTo(EntityType entityType, ConversionParams params, ConversionParams.AfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason) { ++ return this.convertTo(entityType, params, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, creatureSpawnReason); + } + -+ public @Nullable T convertTo(EntityType entityType, ConversionParams conversionParams, ConversionParams.CancellingAfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason) { -+ return this.convertTo(entityType, conversionParams, EntitySpawnReason.CONVERSION, afterConversion, transformReason, creatureSpawnReason); ++ public @Nullable T convertTo(EntityType entityType, ConversionParams params, ConversionParams.CancellingAfterConversion afterConversion, EntityTransformEvent.@Nullable TransformReason transformReason, CreatureSpawnEvent.@Nullable SpawnReason creatureSpawnReason) { ++ return this.convertTo(entityType, params, EntitySpawnReason.CONVERSION, afterConversion, transformReason, creatureSpawnReason); + // Paper end - entity zap event - allow cancellation of conversion post creation } @Override -@@ -1261,7 +_,17 @@ - public boolean startRiding(Entity entity, boolean force, boolean triggerEvents) { - boolean flag = super.startRiding(entity, force, triggerEvents); - if (flag && this.isLeashed()) { +@@ -1276,7 +_,17 @@ + public boolean startRiding(final Entity entity, final boolean force, final boolean sendEventAndTriggers) { + boolean result = super.startRiding(entity, force, sendEventAndTriggers); + if (result && this.isLeashed()) { - this.dropLeash(); + // Paper start - Expand EntityUnleashEvent + EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true); + if (!event.callEvent()) { -+ return flag; ++ return result; + } + if (event.isDropLeash()) { + this.dropLeash(); @@ -437,13 +430,13 @@ + // Paper end - Expand EntityUnleashEvent } - return flag; -@@ -1426,7 +_,7 @@ - List list = new ArrayList<>(availableGoals.size()); + return result; +@@ -1439,7 +_,7 @@ + Set availableGoals = this.goalSelector.getAvailableGoals(); + List goalInfo = new ArrayList<>(availableGoals.size()); availableGoals.forEach( - wrappedGoal -> list.add( -- new DebugGoalInfo.DebugGoal(wrappedGoal.getPriority(), wrappedGoal.isRunning(), wrappedGoal.getGoal().getClass().getSimpleName()) -+ new DebugGoalInfo.DebugGoal(wrappedGoal.getPriority(), wrappedGoal.isRunning(), wrappedGoal.getGoal() instanceof final com.destroystokyo.paper.entity.ai.PaperCustomGoal customGoal ? customGoal.getHandle().getClass().getSimpleName() + "*" : wrappedGoal.getGoal().getClass().getSimpleName()) // Paper - display right custom goal in debugging - ) +- goal -> goalInfo.add(new DebugGoalInfo.DebugGoal(goal.getPriority(), goal.isRunning(), goal.getGoal().getClass().getSimpleName())) ++ goal -> goalInfo.add(new DebugGoalInfo.DebugGoal(goal.getPriority(), goal.isRunning(), goal.getGoal() instanceof final com.destroystokyo.paper.entity.ai.PaperCustomGoal customGoal ? customGoal.getHandle().getClass().getSimpleName() + "*" : goal.getGoal().getClass().getSimpleName())) // Paper - display right custom goal in debugging ); - return new DebugGoalInfo(list); + return new DebugGoalInfo(goalInfo); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch index 1cdc0f94f540..d225c0e9b8a8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/NeutralMob.java +++ b/net/minecraft/world/entity/NeutralMob.java -@@ -50,7 +_,11 @@ +@@ -51,7 +_,11 @@ if (level instanceof ServerLevel) { this.setPersistentAngerTarget(EntityReference.read(input, "angry_at")); @@ -13,26 +13,7 @@ } } -@@ -61,11 +_,16 @@ - this.stopBeingAngry(); - } else { - if (target != null) { -- if (persistentAngerTarget == null || !persistentAngerTarget.matches(target)) { -+ // Paper start - Backport fix for MC-305388 from 26.1-snapshot-5 -+ boolean newTarget = persistentAngerTarget == null || !persistentAngerTarget.matches(target); -+ if (newTarget) { - this.setPersistentAngerTarget(EntityReference.of(target)); - } - -- this.startPersistentAngerTimer(); -+ if (newTarget || updateAnger) { -+ this.startPersistentAngerTimer(); -+ } -+ // Paper end - Backport fix for MC-305388 from 26.1-snapshot-5 - } - - if (persistentAngerTarget != null && !this.isAngry() && (target == null || !isValidPlayerTarget(target) || !updateAnger)) { -@@ -120,7 +_,7 @@ +@@ -134,7 +_,7 @@ default void stopBeingAngry() { this.setLastHurtByMob(null); this.setPersistentAngerTarget(null); @@ -41,15 +22,17 @@ this.setPersistentAngerEndTime(-1L); } -@@ -130,7 +_,19 @@ +@@ -144,9 +_,21 @@ - void setTarget(@Nullable LivingEntity target); + void setTarget(final @Nullable LivingEntity target); + boolean setTarget(@Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason); // CraftBukkit + - boolean canAttack(LivingEntity entity); + boolean canAttack(final LivingEntity target); @Nullable LivingEntity getTarget(); + + @Nullable LivingEntity getTargetUnchecked(); + + // Paper start - Prevent entity loading causing async lookups + // Update last hurt when ticking diff --git a/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch index e3f3fdd9e410..5fc22c0ceaf4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/entity/OminousItemSpawner.java +++ b/net/minecraft/world/entity/OminousItemSpawner.java @@ -78,7 +_,7 @@ - entity = this.spawnProjectile(serverLevel, projectileItem, item); + spawnedEntity = this.spawnProjectile(level, projectileItem, item); } else { - entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), item); -- serverLevel.addFreshEntity(entity); -+ serverLevel.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API + spawnedEntity = new ItemEntity(level, this.getX(), this.getY(), this.getZ(), item); +- level.addFreshEntity(spawnedEntity); ++ level.addFreshEntity(spawnedEntity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API } - serverLevel.levelEvent(LevelEvent.PARTICLES_TRIAL_SPAWNER_SPAWN_ITEM, this.blockPosition(), 1); + level.levelEvent(LevelEvent.PARTICLES_TRIAL_SPAWNER_SPAWN_ITEM, this.blockPosition(), 1); @@ -92,7 +_,7 @@ ProjectileItem.DispenseConfig dispenseConfig = projectileItem.createDispenseConfig(); - dispenseConfig.overrideDispenseEvent().ifPresent(i -> level.levelEvent(i, this.blockPosition(), 0)); + dispenseConfig.overrideDispenseEvent().ifPresent(event -> level.levelEvent(event, this.blockPosition(), 0)); Direction direction = Direction.DOWN; - Projectile projectile = Projectile.spawnProjectileUsingShoot( + Projectile projectile = Projectile.spawnProjectileUsingShootDelayed( // Paper - fixes and addition to spawn reason API - projectileItem.asProjectile(level, this.position(), stack, direction), + projectileItem.asProjectile(level, this.position(), item, direction), level, - stack, + item, @@ -101,7 +_,7 @@ direction.getStepZ(), dispenseConfig.power(), diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch index 7ce39abff887..7b511ad56f67 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch @@ -4,15 +4,15 @@ import net.minecraft.world.item.ItemStack; public interface Shearable { -+ default void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { this.shear(level, source, shears); } // Paper - Add drops to shear events - void shear(ServerLevel level, SoundSource source, ItemStack shears); ++ default void shear(ServerLevel level, SoundSource soundSource, ItemStack tool, java.util.List drops) { this.shear(level, soundSource, tool); } // Paper - Add drops to shear events + void shear(ServerLevel level, SoundSource soundSource, ItemStack tool); boolean readyForShearing(); + + net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. + + // Paper start - custom shear drops; ensure all implementing entities override this -+ default java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack shears) { ++ default java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + return java.util.Collections.emptyList(); + } + // Paper end - custom shear drops diff --git a/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch index cc8c0bbb2921..e298b1df0110 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/TamableAnimal.java +++ b/net/minecraft/world/entity/TamableAnimal.java -@@ -75,7 +_,7 @@ +@@ -80,7 +_,7 @@ } this.orderedToSit = input.getBooleanOr("Sitting", false); @@ -9,21 +9,30 @@ } @Override -@@ -133,6 +_,13 @@ +@@ -136,7 +_,7 @@ + protected void feed(final Player player, final InteractionHand hand, final ItemStack itemStack, final float healingFactor, final float defaultHeal) { + FoodProperties foodProperties = itemStack.get(DataComponents.FOOD); + this.usePlayerItem(player, hand, itemStack); +- this.heal(foodProperties != null ? healingFactor * foodProperties.nutrition() : defaultHeal); ++ this.heal(foodProperties != null ? healingFactor * foodProperties.nutrition() : defaultHeal, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason + this.playEatingSound(); } - public void setInSittingPose(boolean sitting) { +@@ -145,6 +_,13 @@ + } + + public void setInSittingPose(final boolean value) { + // Paper start - Add EntityToggleSitEvent -+ this.setInSittingPose(sitting, true); ++ this.setInSittingPose(value, true); + } + -+ public void setInSittingPose(boolean sitting, boolean callEvent) { -+ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; ++ public void setInSittingPose(boolean value, boolean callEvent) { ++ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), value).callEvent()) return; + // Paper end - Add EntityToggleSitEvent - byte b = this.entityData.get(DATA_FLAGS_ID); - if (sitting) { - this.entityData.set(DATA_FLAGS_ID, (byte)(b | 1)); -@@ -213,7 +_,12 @@ + byte current = this.entityData.get(DATA_FLAGS_ID); + if (value) { + this.entityData.set(DATA_FLAGS_ID, (byte)(current | 1)); +@@ -225,7 +_,12 @@ if (this.level() instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.SHOW_DEATH_MESSAGES) && this.getOwner() instanceof ServerPlayer serverPlayer) { @@ -36,8 +45,8 @@ + // Paper end - Add TameableDeathMessageEvent } - super.die(damageSource); -@@ -256,7 +_,14 @@ + super.die(source); +@@ -268,7 +_,14 @@ if (!this.canTeleportTo(new BlockPos(x, y, z))) { return false; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/attributes/AttributeInstance.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/attributes/AttributeInstance.java.patch index 38c76aeede01..36af4acb6414 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/attributes/AttributeInstance.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/attributes/AttributeInstance.java.patch @@ -1,27 +1,27 @@ --- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java +++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java @@ -148,20 +_,20 @@ - double baseValue = this.getBaseValue(); + double base = this.getBaseValue(); - for (AttributeModifier attributeModifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) { -- baseValue += attributeModifier.amount(); -+ baseValue += attributeModifier.amount(); // Paper - destroy speed API - diff on change + for (AttributeModifier modifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) { +- base += modifier.amount(); ++ base += modifier.amount(); // Paper - destroy speed API - diff on change } - double d = baseValue; + double result = base; - for (AttributeModifier attributeModifier1 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) { -- d += baseValue * attributeModifier1.amount(); -+ d += baseValue * attributeModifier1.amount(); // Paper - destroy speed API - diff on change + for (AttributeModifier modifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) { +- result += base * modifier.amount(); ++ result += base * modifier.amount(); // Paper - destroy speed API - diff on change } - for (AttributeModifier attributeModifier1 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) { -- d *= 1.0 + attributeModifier1.amount(); -+ d *= 1.0 + attributeModifier1.amount(); // Paper - destroy speed API - diff on change + for (AttributeModifier modifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) { +- result *= 1.0 + modifier.amount(); ++ result *= 1.0 + modifier.amount(); // Paper - destroy speed API - diff on change } -- return this.attribute.value().sanitizeValue(d); -+ return this.attribute.value().sanitizeValue(d); // Paper - destroy speed API - diff on change +- return this.attribute.value().sanitizeValue(result); ++ return this.attribute.value().sanitizeValue(result); // Paper - destroy speed API - diff on change } - private Collection getModifiersOrEmpty(AttributeModifier.Operation operation) { + private Collection getModifiersOrEmpty(final AttributeModifier.Operation operation) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch index 2e67b4cf3bf1..e4e2c1f5d828 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -69,6 +_,7 @@ - return false; - } else { - mutableLong.setValue(time + 20L + level.getRandom().nextInt(20)); -+ if (level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.enabled() && mob.getNavigation().isStuck()) mutableLong.add(level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.intValue()); // Paper - Next stuck check delay config - PoiManager poiManager = level.getPoiManager(); - map.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(time)); - Predicate predicate1 = pos -> { +@@ -74,6 +_,7 @@ + return false; + } else { + nextScheduledStart.setValue(timestamp + 20L + random.nextInt(20)); ++ if (level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.enabled() && body.getNavigation().isStuck()) nextScheduledStart.add(level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.intValue()); // Paper - Next stuck check delay config + PoiManager poiManager = level.getPoiManager(); + batchCache.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(timestamp)); + Predicate cacheTest = pos -> { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch index cfc60b55d7ee..d6f0def83860 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch @@ -3,16 +3,16 @@ @@ -39,7 +_,14 @@ .findFirst() ) - .ifPresent(reference -> { -- villager.setVillagerData(villager.getVillagerData().withProfession(reference)); + .ifPresent(profession -> { +- body.setVillagerData(body.getVillagerData().withProfession(profession)); + // CraftBukkit start - Fire VillagerCareerChangeEvent where Villager gets employed -+ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(villager, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(reference), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.EMPLOYED); ++ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(body, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(profession), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.EMPLOYED); + if (event.isCancelled()) { + return; + } + -+ villager.setVillagerData(villager.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); ++ body.setVillagerData(body.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); + // CraftBukkit end - villager.refreshBrain(level); + body.refreshBrain(level); }); return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java.patch index 1ba0031bec4f..76dd72d72617 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java +++ b/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java -@@ -30,6 +_,17 @@ +@@ -28,6 +_,17 @@ } else { - LivingEntity livingEntity = instance.get(memoryAccessor); - if (entity.closerThan(livingEntity, followRange.getMaxValue() + 1) && !entity.closerThan(livingEntity, followRange.getMinValue())) { + LivingEntity adult = i.get(nearestAdult); + if (body.closerThan(adult, followRange.maxInclusive() + 1) && !body.closerThan(adult, followRange.minInclusive())) { + // CraftBukkit start -+ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(entity, livingEntity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); ++ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, adult, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); + if (event.isCancelled()) { + return false; + } + if (event.getTarget() == null) { -+ memoryAccessor.erase(); ++ walkTarget.erase(); + return true; + } -+ livingEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); ++ adult = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); + // CraftBukkit end - WalkTarget walkTarget = new WalkTarget( - new EntityTracker(livingEntity, targetEyeHeight, targetEyeHeight), - speedModifier.apply(entity), + WalkTarget target = new WalkTarget( + new EntityTracker(adult, targetEye, targetEye), speedModifier.apply(body), followRange.minInclusive() - 1 + ); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/Behavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/Behavior.java.patch index 5088503a0803..d8f3e1a2ea3a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/Behavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/Behavior.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/net/minecraft/world/entity/ai/behavior/Behavior.java -@@ -14,6 +_,7 @@ +@@ -15,6 +_,7 @@ private long endTimestamp; private final int minDuration; private final int maxDuration; + private final String configKey; // Paper - configurable behavior tick rate and timings - public Behavior(Map, MemoryStatus> entryCondition) { + public Behavior(final Map, MemoryStatus> entryCondition) { this(entryCondition, 60); -@@ -27,6 +_,14 @@ +@@ -28,6 +_,14 @@ this.minDuration = minDuration; this.maxDuration = maxDuration; this.entryCondition = entryCondition; + // Paper start - configurable behavior tick rate and timings -+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); ++ String key = this.getClass().getName(); + int lastSeparator = key.lastIndexOf('.'); + if (lastSeparator != -1) { + key = key.substring(lastSeparator + 1); @@ -23,16 +23,16 @@ } @Override -@@ -36,6 +_,12 @@ +@@ -42,6 +_,12 @@ @Override - public final boolean tryStart(ServerLevel level, E owner, long gameTime) { + public final boolean tryStart(final ServerLevel level, final E body, final long timestamp) { + // Paper start - configurable behavior tick rate and timings -+ int tickRate = java.util.Objects.requireNonNullElse(level.paperConfig().tickRates.behavior.get(owner.getType(), this.configKey), -1); -+ if (tickRate > -1 && gameTime < this.endTimestamp + tickRate) { ++ int tickRate = java.util.Objects.requireNonNullElse(level.paperConfig().tickRates.behavior.get(body.getType(), this.configKey), -1); ++ if (tickRate > -1 && timestamp < this.endTimestamp + tickRate) { + return false; + } + // Paper end - configurable behavior tick rate and timings - if (this.hasRequiredMemories(owner) && this.checkExtraStartConditions(level, owner)) { + if (this.hasRequiredMemories(body) && this.checkExtraStartConditions(level, body)) { this.status = Behavior.Status.RUNNING; - int i = this.minDuration + level.getRandom().nextInt(this.maxDuration + 1 - this.minDuration); + int duration = this.minDuration + level.getRandom().nextInt(this.maxDuration + 1 - this.minDuration); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java.patch index 77f8530cc4ed..d25530175304 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java.patch @@ -1,24 +1,24 @@ --- a/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java +++ b/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java -@@ -80,6 +_,7 @@ - } - - public static void throwItem(LivingEntity entity, ItemStack stack, Vec3 offset, Vec3 speedMultiplier, float yOffset) { -+ if (stack.isEmpty()) return; // CraftBukkit - SPIGOT-4940: no empty loot - double d = entity.getEyeY() - yOffset; - ItemEntity itemEntity = new ItemEntity(entity.level(), entity.getX(), d, entity.getZ(), stack); - itemEntity.setThrower(entity); -@@ -87,6 +_,13 @@ - vec3 = vec3.normalize().multiply(speedMultiplier.x, speedMultiplier.y, speedMultiplier.z); - itemEntity.setDeltaMovement(vec3); +@@ -94,6 +_,7 @@ + public static void throwItem( + final LivingEntity thrower, final ItemStack item, final Vec3 targetPos, final Vec3 throwVelocity, final float handYDistanceFromEye + ) { ++ if (item.isEmpty()) return; // CraftBukkit - SPIGOT-4940: no empty loot + double yHandPos = thrower.getEyeY() - handYDistanceFromEye; + ItemEntity itemEntity = new ItemEntity(thrower.level(), thrower.getX(), yHandPos, thrower.getZ(), item); + itemEntity.setThrower(thrower); +@@ -101,6 +_,13 @@ + throwVector = throwVector.normalize().multiply(throwVelocity.x, throwVelocity.y, throwVelocity.z); + itemEntity.setDeltaMovement(throwVector); itemEntity.setDefaultPickUpDelay(); + // CraftBukkit start -+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(entity.getBukkitEntity(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(thrower.getBukkitEntity(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); + itemEntity.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + // CraftBukkit end - entity.level().addFreshEntity(itemEntity); + thrower.level().addFreshEntity(itemEntity); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch index d7a1d368e053..736ebb2919f8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java -@@ -18,7 +_,7 @@ +@@ -19,7 +_,7 @@ private final Set> exitErasedMemories; private final GateBehavior.OrderPolicy orderPolicy; private final GateBehavior.RunningPolicy runningPolicy; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java.patch index b4c97cad9b5f..f70e5c7e3a59 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java.patch @@ -1,24 +1,24 @@ --- a/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java +++ b/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java -@@ -35,6 +_,21 @@ - && itemEntity.closerThan(entity, maxDistToWalk) - && entity.level().getWorldBorder().isWithinBounds(itemEntity.blockPosition()) - && entity.canPickUpLoot()) { +@@ -37,6 +_,21 @@ + && item.closerThan(body, maxDistToWalk) + && body.level().getWorldBorder().isWithinBounds(item.blockPosition()) + && body.canPickUpLoot()) { + // CraftBukkit start -+ if (entity instanceof net.minecraft.world.entity.animal.allay.Allay) { -+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetEvent(entity, itemEntity, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); ++ if (body instanceof net.minecraft.world.entity.animal.allay.Allay) { ++ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetEvent(body, item, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); + + if (event.isCancelled()) { + return false; + } + if (!(event.getTarget() instanceof org.bukkit.craftbukkit.entity.CraftItem targetItem)) { // Paper - only erase allay memory on non-item targets -+ nearestVisibleWantedItem.erase(); ++ wantedItem.erase(); + return false; // Paper - only erase allay memory on non-item targets + } + -+ itemEntity = targetItem.getHandle(); ++ item = targetItem.getHandle(); + } + // CraftBukkit end - WalkTarget walkTarget1 = new WalkTarget(new EntityTracker(itemEntity, false), speedModifier, 0); - lookTarget.set(new EntityTracker(itemEntity, true)); - walkTarget.set(walkTarget1); + WalkTarget target = new WalkTarget(new EntityTracker(item, false), speedModifier, 0); + lookTarget.set(new EntityTracker(item, true)); + walkTarget.set(target); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch index 4f07a53c89a7..8d8868ad1659 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch @@ -2,23 +2,23 @@ +++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java @@ -108,7 +_,9 @@ Block block = blockState.getBlock(); - Block block1 = level.getBlockState(this.aboveFarmlandPos.below()).getBlock(); + Block blockBelow = level.getBlockState(this.aboveFarmlandPos.below()).getBlock(); if (block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(owner, this.aboveFarmlandPos, blockState.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state - level.destroyBlock(this.aboveFarmlandPos, true, owner); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(body, this.aboveFarmlandPos, blockState.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state + level.destroyBlock(this.aboveFarmlandPos, true, body); + } // CraftBukkit } - if (blockState.isAir() && block1 instanceof FarmBlock && owner.hasFarmSeeds()) { + if (blockState.isAir() && blockBelow instanceof FarmlandBlock && body.hasFarmSeeds()) { @@ -119,9 +_,11 @@ - boolean flag = false; - if (!item.isEmpty() && item.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) && item.getItem() instanceof BlockItem blockItem) { - BlockState blockState1 = blockItem.getBlock().defaultBlockState(); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(owner, this.aboveFarmlandPos, blockState1)) { // CraftBukkit - level.setBlockAndUpdate(this.aboveFarmlandPos, blockState1); - level.gameEvent(GameEvent.BLOCK_PLACE, this.aboveFarmlandPos, GameEvent.Context.of(owner, blockState1)); - flag = true; + boolean ok = false; + if (!itemStack.isEmpty() && itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) && itemStack.getItem() instanceof BlockItem blockItem) { + BlockState place = blockItem.getBlock().defaultBlockState(); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(body, this.aboveFarmlandPos, place)) { // CraftBukkit + level.setBlockAndUpdate(this.aboveFarmlandPos, place); + level.gameEvent(GameEvent.BLOCK_PLACE, this.aboveFarmlandPos, GameEvent.Context.of(body, place)); + ok = true; + } // CraftBukkit } - if (flag) { + if (ok) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch index 05862afb2985..fa4f0576a159 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java +++ b/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java -@@ -58,6 +_,12 @@ - if (blockState.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)) { - DoorBlock doorBlock = (DoorBlock)blockState.getBlock(); - if (!doorBlock.isOpen(blockState)) { +@@ -56,6 +_,12 @@ + if (fromState.is(BlockTags.MOB_INTERACTABLE_DOORS, s -> s.getBlock() instanceof DoorBlock)) { + DoorBlock fromBlock = (DoorBlock)fromState.getBlock(); + if (!fromBlock.isOpen(fromState)) { + // CraftBukkit start - entities opening doors -+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), blockPos)); ++ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(body.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(body.level(), fromPos)); + if (!event.callEvent()) { + return false; + } + // CraftBukkit end - entities opening doors - doorBlock.setOpen(entity, level, blockState, blockPos, true); + fromBlock.setOpen(body, level, fromState, fromPos, true); } -@@ -69,6 +_,12 @@ - if (blockState1.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)) { - DoorBlock doorBlock1 = (DoorBlock)blockState1.getBlock(); - if (!doorBlock1.isOpen(blockState1)) { +@@ -67,6 +_,12 @@ + if (toState.is(BlockTags.MOB_INTERACTABLE_DOORS, s -> s.getBlock() instanceof DoorBlock)) { + DoorBlock door = (DoorBlock)toState.getBlock(); + if (!door.isOpen(toState)) { + // CraftBukkit start - entities opening doors -+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), blockPos1)); ++ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(body.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(body.level(), toPos)); + if (!event.callEvent()) { + return false; + } + // CraftBukkit end - entities opening doors - doorBlock1.setOpen(entity, level, blockState1, blockPos1, true); - optional = rememberDoorToClose(doorsToClose, optional, level, blockPos1); + door.setOpen(body, level, toState, toPos, true); + doors = rememberDoorToClose(doorsMemory, doors, level, toPos); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java.patch index 2158504f91e1..caaee018aa0c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java.patch @@ -2,35 +2,35 @@ +++ b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java @@ -22,13 +_,32 @@ level.getPoiManager() - .getType(globalPos.pos()) + .getType(pos.pos()) .ifPresent( -- poi -> instance.>get(nearestLivingEntities) +- poiType -> i.>get(nearestEntities) - .stream() -- .filter(entity -> entity instanceof Villager && entity != villager) -- .map(entity -> (Villager)entity) +- .filter(v -> v instanceof Villager && v != body) +- .map(v -> (Villager)v) - .filter(LivingEntity::isAlive) -- .filter(v -> competesForSameJobsite(globalPos, poi, v)) -- .reduce(villager, PoiCompetitorScan::selectWinner) +- .filter(nearbyVillager -> competesForSameJobsite(pos, poiType, nearbyVillager)) +- .reduce(body, PoiCompetitorScan::selectWinner) + // Paper start - Improve performance of PoiCompetitorScan by unrolling stream + // The previous logic used Stream#reduce to simulate a form of single-iteration bubble sort + // in which the "winning" villager would maintain MemoryModuleType.JOB_SITE while all others + // would lose said memory module type by passing each "current winner" and incoming next + // villager to #selectWinner. -+ poi -> { -+ final List livingEntities = instance.get(nearestLivingEntities); ++ poiType -> { ++ final List livingEntities = i.get(nearestEntities); + -+ Villager winner = villager; ++ Villager winner = body; + for (final LivingEntity other : livingEntities) { -+ if (other == villager) { ++ if (other == body) { + continue; + } -+ if (!(other instanceof final net.minecraft.world.entity.npc.villager.Villager otherVillager)) { ++ if (!(other instanceof final Villager otherVillager)) { + continue; + } + if (!other.isAlive()) { + continue; + } -+ if (!competesForSameJobsite(globalPos, poi, otherVillager)) { ++ if (!competesForSameJobsite(pos, poiType, otherVillager)) { + continue; + } + winner = selectWinner(winner, otherVillager); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java.patch index 7a3f753af534..ec955530a856 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java +++ b/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java -@@ -76,6 +_,16 @@ - .flatMap( - nearestVisibleLivingEntities -> nearestVisibleLivingEntities.findClosest(livingEntity -> this.ramTargeting.test(level, entity, livingEntity)) - ) +@@ -74,6 +_,16 @@ + Brain brain = body.getBrain(); + brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) + .flatMap(livingEntities -> livingEntities.findClosest(entity -> this.ramTargeting.test(level, body, entity))) + // CraftBukkit start + .map((livingEntity) -> { -+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(entity, livingEntity, (livingEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); ++ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, livingEntity, (livingEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); + if (event.isCancelled() || event.getTarget() == null) { + return null; + } @@ -14,6 +14,6 @@ + return livingEntity; + }) + // CraftBukkit end - .ifPresent(entity1 -> this.chooseRamPosition(entity, entity1)); + .ifPresent(livingEntity -> this.chooseRamPosition(body, livingEntity)); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/RamTarget.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/RamTarget.java.patch index f1551b7ce4ca..e0768185f551 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/RamTarget.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/RamTarget.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/ai/behavior/RamTarget.java +++ b/net/minecraft/world/entity/ai/behavior/RamTarget.java @@ -93,7 +_,7 @@ - DamageSource damageSource1 = level.damageSources().mobAttack(owner); - float f3 = livingEntity.applyItemBlocking(level, damageSource1, f); - float f4 = f3 > 0.0F ? 0.5F : 1.0F; -- livingEntity.knockback(f4 * f2 * this.getKnockbackForce.applyAsDouble(owner), this.ramDirection.x(), this.ramDirection.z()); -+ livingEntity.knockback(f4 * f2 * this.getKnockbackForce.applyAsDouble(owner), this.ramDirection.x(), this.ramDirection.z(), owner, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - this.finishRam(level, owner); - level.playSound(null, owner, this.getImpactSound.apply(owner), SoundSource.NEUTRAL, 1.0F, 1.0F); - } else if (this.hasRammedHornBreakingBlock(level, owner)) { + DamageSource source = level.damageSources().mobAttack(body); + float blockedDamage = ramTarget.applyItemBlocking(level, source, damage); + float blockingFactor = blockedDamage > 0.0F ? 0.5F : 1.0F; +- ramTarget.knockback(blockingFactor * speedFactor * this.getKnockbackForce.applyAsDouble(body), this.ramDirection.x(), this.ramDirection.z()); ++ ramTarget.knockback(blockingFactor * speedFactor * this.getKnockbackForce.applyAsDouble(body), this.ramDirection.x(), this.ramDirection.z(), body, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + this.finishRam(level, body); + level.playSound(null, body, this.getImpactSound.apply(body), SoundSource.NEUTRAL, 1.0F, 1.0F); + } else if (this.hasRammedHornBreakingBlock(level, body)) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ResetProfession.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ResetProfession.java.patch index 00704ac6966f..0bc02b959fdf 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ResetProfession.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ResetProfession.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/entity/ai/behavior/ResetProfession.java +++ b/net/minecraft/world/entity/ai/behavior/ResetProfession.java -@@ -13,7 +_,14 @@ - VillagerData villagerData = villager.getVillagerData(); - boolean flag = !villagerData.profession().is(VillagerProfession.NONE) && !villagerData.profession().is(VillagerProfession.NITWIT); - if (flag && villager.getVillagerXp() == 0 && villagerData.level() <= 1) { -- villager.setVillagerData(villager.getVillagerData().withProfession(level.registryAccess(), VillagerProfession.NONE)); -+ // CraftBukkit start -+ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(villager, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(level.registryAccess().getOrThrow(VillagerProfession.NONE)), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.LOSING_JOB); -+ if (event.isCancelled()) { -+ return false; -+ } +@@ -12,7 +_,14 @@ + VillagerData bodyData = body.getVillagerData(); + boolean canBeFired = !bodyData.profession().is(VillagerProfession.NONE) && !bodyData.profession().is(VillagerProfession.NITWIT); + if (canBeFired && body.getVillagerXp() == 0 && bodyData.level() <= 1) { +- body.setVillagerData(body.getVillagerData().withProfession(level.registryAccess(), VillagerProfession.NONE)); ++ // CraftBukkit start ++ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(body, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(level.registryAccess().getOrThrow(VillagerProfession.NONE)), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.LOSING_JOB); ++ if (event.isCancelled()) { ++ return false; ++ } + -+ villager.setVillagerData(villager.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); -+ // CraftBukkit end - villager.refreshBrain(level); - return true; - } else { ++ body.setVillagerData(body.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); ++ // CraftBukkit end + body.refreshBrain(level); + return true; + } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch index ddad0d36980c..fccff1ee82d3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch @@ -16,7 +16,7 @@ this.entries = Lists.newArrayList(); } - private ShufflingList(List> entries) { + private ShufflingList(final List> entries) { + // Paper start - Fix Concurrency issue in ShufflingList during worldgen + this(entries, true); + } @@ -30,12 +30,12 @@ } public ShufflingList shuffle() { -- this.entries.forEach(entry -> entry.setRandom(this.random.nextFloat())); +- this.entries.forEach(k -> k.setRandom(this.random.nextFloat())); - this.entries.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); - return this; + // Paper start - Fix Concurrency issue in ShufflingList during worldgen + List> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries; -+ list.forEach(entry -> entry.setRandom(this.random.nextFloat())); ++ list.forEach(k -> k.setRandom(this.random.nextFloat())); + list.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); + return this.isUnsafe ? new ShufflingList<>(list, this.isUnsafe) : this; + // Paper end - Fix Concurrency issue in ShufflingList during worldgen diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch index cfe4ec05792b..c293d55736e8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/ai/behavior/SleepInBed.java +++ b/net/minecraft/world/entity/ai/behavior/SleepInBed.java -@@ -42,7 +_,8 @@ +@@ -55,7 +_,8 @@ } } -- BlockState blockState = level.getBlockState(globalPos.pos()); -+ BlockState blockState = level.getBlockStateIfLoaded(globalPos.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds +- BlockState blockState = level.getBlockState(target.pos()); ++ BlockState blockState = level.getBlockStateIfLoaded(target.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds + if (blockState == null) { return false; } // Paper - Prevent sync chunk loads when villagers try to find beds - return globalPos.pos().closerToCenterThan(owner.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED); + return target.pos().closerToCenterThan(body.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch index 4915d1fd6b44..8dcd2a659c5e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/entity/ai/behavior/StartAttacking.java +++ b/net/minecraft/world/entity/ai/behavior/StartAttacking.java -@@ -27,6 +_,17 @@ - if (!entity.canAttack(livingEntity)) { +@@ -29,6 +_,17 @@ + if (!body.canAttack(targetEntity)) { return false; } else { + // CraftBukkit start -+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(entity, livingEntity, (livingEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); ++ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, targetEntity, (targetEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); + if (event.isCancelled()) { + return false; + } + if (event.getTarget() == null) { -+ memoryAccessor.erase(); ++ attackTarget.erase(); + return true; + } -+ livingEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); ++ targetEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); + // CraftBukkit end - memoryAccessor.set(livingEntity); - memoryAccessor1.erase(); + attackTarget.set(targetEntity); + cantReachSince.erase(); return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch index 24a503eca08c..92fca8fa6ab9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch @@ -1,33 +1,33 @@ --- a/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java +++ b/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java @@ -40,6 +_,30 @@ - && !canStopAttacking.test(level, livingEntity)) { + && !stopAttackingWhen.test(level, target)) { return true; } else { + // Paper start - better track target change reason + final org.bukkit.event.entity.EntityTargetEvent.TargetReason reason; -+ if (!entity.canAttack(livingEntity)) { ++ if (!body.canAttack(target)) { + reason = org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID; -+ } else if (canGrowTiredOfTryingToReachTarget && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entity, instance.tryGet(memoryAccessor1))) { ++ } else if (canGrowTiredOfTryingToReachTarget && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(body, i.tryGet(cantReachSince))) { + reason = org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET; -+ } else if (!livingEntity.isAlive()) { ++ } else if (!target.isAlive()) { + reason = org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_DIED; -+ } else if (livingEntity.level() != entity.level()) { ++ } else if (target.level() != body.level()) { + reason = org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL; + } else { + reason = org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_INVALID; + } + // Paper end + // CraftBukkit start -+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(entity, null, reason); // Paper ++ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, null, reason); // Paper + if (event.isCancelled()) { + return false; + } + if (event.getTarget() != null) { -+ entity.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle()); ++ body.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle()); + return true; + } + // CraftBukkit end - onStopAttacking.accept(level, entity, livingEntity); - memoryAccessor.erase(); + onTargetErased.accept(level, body, target); + attackTarget.erase(); return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch index 6d62fb17905f..14091cbbf463 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java +++ b/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java -@@ -320,7 +_,10 @@ +@@ -326,7 +_,10 @@ } else { - boolean flag1 = this.isWantedBlock(mob, transportItemTarget.state) + boolean isValidTarget = this.isWantedBlock(body, transportItemTarget.state) && !this.isPositionAlreadyVisited(visitedPositions, unreachablePositions, transportItemTarget, level) - && !this.isContainerLocked(transportItemTarget); + // Paper start - ItemTransportingEntityValidateTargetEvent + && !this.isContainerLocked(transportItemTarget) -+ && org.bukkit.craftbukkit.event.CraftEventFactory.callTransporterValidateTarget(mob, level, transportItemTarget.pos); ++ && org.bukkit.craftbukkit.event.CraftEventFactory.callTransporterValidateTarget(body, level, transportItemTarget.pos); + // Paper end - ItemTransportingEntityValidateTargetEvent - return flag1 ? transportItemTarget : null; + return isValidTarget ? transportItemTarget : null; } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnFluidNearLand.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnFluidNearLand.java.patch new file mode 100644 index 000000000000..6660933f61d9 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnFluidNearLand.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnFluidNearLand.java ++++ b/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnFluidNearLand.java +@@ -33,6 +_,12 @@ + BlockPos spawnPos = relativePos.above(); + if (level.getBlockState(spawnPos).isAir()) { + BlockState newState = spawnBlock.defaultBlockState(); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(body, spawnPos, newState)) { ++ pregnant.erase(); ++ return true; ++ } ++ // CraftBukkit end + level.setBlock(spawnPos, newState, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_PLACE, spawnPos, GameEvent.Context.of(body, newState)); + level.playSound(null, body, SoundEvents.FROG_LAY_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java.patch deleted file mode 100644 index be0a7c556113..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java -+++ b/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java -@@ -33,6 +_,12 @@ - BlockPos blockPos2 = blockPos1.above(); - if (level.getBlockState(blockPos2).isAir()) { - BlockState blockState = spawnBlock.defaultBlockState(); -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos2, blockState)) { -+ isPregnant.erase(); -+ return true; -+ } -+ // CraftBukkit end - level.setBlock(blockPos2, blockState, Block.UPDATE_ALL); - level.gameEvent(GameEvent.BLOCK_PLACE, blockPos2, GameEvent.Context.of(entity, blockState)); - level.playSound(null, entity, SoundEvents.FROG_LAY_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch index 0a009423ec25..8e0b0d1a4dcc 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java +++ b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -@@ -111,11 +_,17 @@ - if (breedOffspring == null) { +@@ -110,11 +_,17 @@ + if (child == null) { return Optional.empty(); } else { -- parent.setAge(6000); -- partner.setAge(6000); - breedOffspring.setAge(-24000); +- source.setAge(6000); +- target.setAge(6000); + child.setAge(-24000); + // Paper - Move age setting down - breedOffspring.snapTo(parent.getX(), parent.getY(), parent.getZ(), 0.0F, 0.0F); -- level.addFreshEntityWithPassengers(breedOffspring); + child.snapTo(source.getX(), source.getY(), source.getZ(), 0.0F, 0.0F); +- level.addFreshEntityWithPassengers(child); + // CraftBukkit start - call EntityBreedEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, parent, partner, null, null, 0).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(child, source, target, null, null, 0).isCancelled()) { + return Optional.empty(); + } -+ parent.setAge(6000); -+ partner.setAge(6000); -+ level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); ++ source.setAge(6000); ++ target.setAge(6000); ++ level.addFreshEntityWithPassengers(child, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); + // CraftBukkit end - call EntityBreedEvent - level.broadcastEntityEvent(breedOffspring, EntityEvent.LOVE_HEARTS); - return Optional.of(breedOffspring); + level.broadcastEntityEvent(child, EntityEvent.LOVE_HEARTS); + return Optional.of(child); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java.patch index 55a834a3c650..80f6741907df 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java +++ b/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java @@ -87,7 +_,9 @@ - inventory.removeItemType(Items.WHEAT, i3); - ItemStack itemStack = inventory.addItem(new ItemStack(Items.BREAD, min)); - if (!itemStack.isEmpty()) { -+ villager.forceDrops = true; // Paper - Add missing forceDrop toggles - villager.spawnAtLocation(level, itemStack, 0.5F); -+ villager.forceDrops = false; // Paper - Add missing forceDrop toggles + inventory.removeItemType(Items.WHEAT, howMuchWheatToUse); + ItemStack breadICantCarry = inventory.addItem(new ItemStack(Items.BREAD, howMuchBreadToMake)); + if (!breadICantCarry.isEmpty()) { ++ body.forceDrops = true; // Paper - Add missing forceDrop toggles + body.spawnAtLocation(level, breadICantCarry, 0.5F); ++ body.forceDrops = false; // Paper - Add missing forceDrop toggles } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/Digging.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/Digging.java.patch index c571e45b5ed3..797cbc0d9ce7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/Digging.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/Digging.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/entity/ai/behavior/warden/Digging.java @@ -39,7 +_,7 @@ @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - if (entity.getRemovalReason() == null) { -- entity.remove(Entity.RemovalReason.DISCARDED); -+ entity.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - Add bukkit remove cause + protected void stop(final ServerLevel level, final E body, final long timestamp) { + if (body.getRemovalReason() == null) { +- body.remove(Entity.RemovalReason.DISCARDED); ++ body.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - Add bukkit remove cause } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java.patch index 37f0c908483d..fb04f9af196f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java +++ b/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java @@ -84,7 +_,7 @@ - if (livingEntity.hurtServer(level, level.damageSources().sonicBoom(owner), 10.0F)) { - double d = 0.5 * (1.0 - livingEntity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); - double d1 = 2.5 * (1.0 - livingEntity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); -- livingEntity.push(vec32.x() * d1, vec32.y() * d, vec32.z() * d1); -+ livingEntity.push(vec32.x() * d1, vec32.y() * d, vec32.z() * d1, owner); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + if (target.hurtServer(level, level.damageSources().sonicBoom(body), 10.0F)) { + double knockbackVertical = 0.5 * (1.0 - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); + double knockbackHorizontal = 2.5 * (1.0 - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); +- target.push(normalize.x() * knockbackHorizontal, normalize.y() * knockbackVertical, normalize.z() * knockbackHorizontal); ++ target.push(normalize.x() * knockbackHorizontal, normalize.y() * knockbackVertical, normalize.z() * knockbackHorizontal, body); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent } }); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/EatBlockGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/EatBlockGoal.java.patch index 4ecb07b24c57..fff4a9b18ff1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/EatBlockGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/EatBlockGoal.java.patch @@ -3,21 +3,21 @@ @@ -62,8 +_,9 @@ this.eatAnimationTick = Math.max(0, this.eatAnimationTick - 1); if (this.eatAnimationTick == this.adjustedTickDelay(4)) { - BlockPos blockPos = this.mob.blockPosition(); -- if (IS_EDIBLE.test(this.level.getBlockState(blockPos))) { + BlockPos pos = this.mob.blockPosition(); +- if (IS_EDIBLE.test(this.level.getBlockState(pos))) { - if (getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING)) { -+ final BlockState blockState = this.level.getBlockState(blockPos); // Paper - fix wrong block state ++ final BlockState blockState = this.level.getBlockState(pos); // Paper - fix wrong block state + if (IS_EDIBLE.test(blockState)) { // Paper - fix wrong block state -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - fix wrong block state - this.level.destroyBlock(blockPos, false); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, pos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - fix wrong block state + this.level.destroyBlock(pos, false); } @@ -71,7 +_,7 @@ } else { - BlockPos blockPos1 = blockPos.below(); - if (this.level.getBlockState(blockPos1).is(Blocks.GRASS_BLOCK)) { + BlockPos below = pos.below(); + if (this.level.getBlockState(below).is(Blocks.GRASS_BLOCK)) { - if (getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - Fix wrong block state - this.level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); - this.level.setBlock(blockPos1, Blocks.DIRT.defaultBlockState(), Block.UPDATE_CLIENTS); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, below, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit // Paper - Fix wrong block state + this.level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, below, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); + this.level.setBlock(below, Blocks.DIRT.defaultBlockState(), Block.UPDATE_CLIENTS); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FloatGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FloatGoal.java.patch index f73e97c9036c..737d4e23de77 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FloatGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FloatGoal.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/entity/ai/goal/FloatGoal.java @@ -9,6 +_,7 @@ - public FloatGoal(Mob mob) { + public FloatGoal(final Mob mob) { this.mob = mob; + if (mob.level().paperConfig().entities.behavior.spawnerNerfedMobsShouldJump) mob.goalFloat = this; // Paper - Allow nerfed mobs to jump and float this.setFlags(EnumSet.of(Goal.Flag.JUMP)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch index 29d8247ac576..f1da063b5129 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java @@ -71,7 +_,7 @@ public void tick() { - boolean shouldTryTeleportToOwner = this.tamable.shouldTryTeleportToOwner(); - if (!shouldTryTeleportToOwner) { + boolean isOwnerFarAway = this.tamable.shouldTryTeleportToOwner(); + if (!isOwnerFarAway) { - this.tamable.getLookControl().setLookAt(this.owner, 10.0F, this.tamable.getMaxHeadXRot()); + if (this.tamable.distanceToSqr(this.owner) <= 16 * 16) this.tamable.getLookControl().setLookAt(this.owner, 10.0F, this.tamable.getMaxHeadXRot()); // Paper - Limit pet look distance } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch index e64289b68543..6a67fd5bf5a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch @@ -15,8 +15,8 @@ + } + // Paper end - Mob Goal API + - protected int adjustedTickDelay(int adjustment) { - return this.requiresUpdateEveryTick() ? adjustment : reducedTickDelay(adjustment); + protected int adjustedTickDelay(final int ticks) { + return this.requiresUpdateEveryTick() ? ticks : reducedTickDelay(ticks); } @@ -62,7 +_,19 @@ return (ServerLevel)level; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch index a42f7a01a855..624465630772 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch @@ -1,40 +1,40 @@ --- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -@@ -104,6 +_,11 @@ +@@ -101,6 +_,11 @@ } if (this.ticksSinceReachedGoal > 60) { + // CraftBukkit start - Step on eggs -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityInteractEvent(this.removerMob, org.bukkit.craftbukkit.block.CraftBlock.at(level, posWithBlock))) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityInteractEvent(this.removerMob, org.bukkit.craftbukkit.block.CraftBlock.at(level, eatPos))) { + return; + } + // CraftBukkit end - level.removeBlock(posWithBlock, false); + level.removeBlock(eatPos, false); if (!level.isClientSide()) { for (int i = 0; i < 20; i++) { -@@ -123,13 +_,16 @@ +@@ -119,13 +_,16 @@ } - private @Nullable BlockPos getPosWithBlock(BlockPos pos, BlockGetter level) { + private @Nullable BlockPos getPosWithBlock(final BlockPos pos, final BlockGetter level) { - if (level.getBlockState(pos).is(this.blockToRemove)) { -+ net.minecraft.world.level.block.state.BlockState block = level.getBlockStateIfLoaded(pos); // Paper - Prevent AI rules from loading chunks -+ if (block == null) return null; // Paper - Prevent AI rules from loading chunks -+ if (block.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks ++ net.minecraft.world.level.block.state.BlockState state = level.getBlockStateIfLoaded(pos); // Paper - Prevent AI rules from loading chunks ++ if (state == null) return null; // Paper - Prevent AI rules from loading chunks ++ if (state.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks return pos; } else { - BlockPos[] blockPoss = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()}; + BlockPos[] neighbours = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()}; - for (BlockPos blockPos : blockPoss) { -- if (level.getBlockState(blockPos).is(this.blockToRemove)) { -+ net.minecraft.world.level.block.state.BlockState block2 = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent AI rules from loading chunks -+ if (block2 != null && block2.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks - return blockPos; + for (BlockPos neighborPos : neighbours) { +- if (level.getBlockState(neighborPos).is(this.blockToRemove)) { ++ net.minecraft.world.level.block.state.BlockState neighborState = level.getBlockStateIfLoaded(neighborPos); // Paper - Prevent AI rules from loading chunks ++ if (neighborState != null && neighborState.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks + return neighborPos; } } -@@ -140,7 +_,7 @@ +@@ -136,7 +_,7 @@ @Override - protected boolean isValidTarget(LevelReader level, BlockPos pos) { + protected boolean isValidTarget(final LevelReader level, final BlockPos pos) { - ChunkAccess chunk = level.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ChunkStatus.FULL, false); + ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks return chunk != null diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch index 402f2ab1caa5..37dbeb0b11d0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java +++ b/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java @@ -59,7 +_,7 @@ - if (firstPassenger instanceof Player player) { + if (passenger instanceof Player player) { int temper = this.horse.getTemper(); int maxTemper = this.horse.getMaxTemper(); - if (maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch index 90559c5ec7ab..ed42ecb6dffa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/entity/ai/goal/SwellGoal.java +++ b/net/minecraft/world/entity/ai/goal/SwellGoal.java @@ -20,6 +_,7 @@ - return this.creeper.getSwellDir() > 0 || target != null && this.creeper.distanceToSqr(target) < 9.0; + return this.creeper.getSwellDir() > 0 || target != null && !target.isDeadOrDying() && this.creeper.distanceToSqr(target) < 9.0; } + @Override public void start() { this.creeper.getNavigation().stop(); -@@ -40,7 +_,7 @@ +@@ -39,7 +_,7 @@ + @Override public void tick() { - if (this.target == null) { - this.creeper.setSwellDir(-1); -- } else if (this.creeper.distanceToSqr(this.target) > 49.0) { -+ } else if (this.creeper.distanceToSqr(this.target) > 49.0 || !net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(this.target)) { // Paper - Fix MC-179072 - consider creative / spectator players as out of reach - this.creeper.setSwellDir(-1); - } else if (!this.creeper.getSensing().hasLineOfSight(this.target)) { - this.creeper.setSwellDir(-1); + if (this.target != null && !this.target.isDeadOrDying()) { +- if (this.creeper.distanceToSqr(this.target) > 49.0) { ++ if (this.creeper.distanceToSqr(this.target) > 49.0 || !net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(this.target)) { // Paper - Fix MC-179072 - consider creative / spectator players as out of reach + this.creeper.setSwellDir(-1); + } else if (!this.creeper.getSensing().hasLineOfSight(this.target)) { + this.creeper.setSwellDir(-1); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch index 1a838aa9c160..230976671c2e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch @@ -29,8 +29,8 @@ this.mob.getNavigation().stop(); } -- protected void navigateTowards(Player player) { -+ protected void navigateTowards(LivingEntity player) { // Paper +- protected void navigateTowards(final Player player) { ++ protected void navigateTowards(final LivingEntity player) { // Paper this.mob.getNavigation().moveTo(player, this.speedModifier); } @@ -38,8 +38,8 @@ } @Override -- protected void navigateTowards(Player player) { -+ protected void navigateTowards(LivingEntity player) { // Paper - Vec3 vec3 = player.getEyePosition().subtract(this.mob.position()).scale(this.mob.getRandom().nextDouble()).add(this.mob.position()); - this.mob.getMoveControl().setWantedPosition(vec3.x, vec3.y, vec3.z, this.speedModifier); +- protected void navigateTowards(final Player player) { ++ protected void navigateTowards(final LivingEntity player) { // Paper + Vec3 target = player.getEyePosition().subtract(this.mob.position()).scale(this.mob.getRandom().nextDouble()).add(this.mob.position()); + this.mob.getMoveControl().setWantedPosition(target.x, target.y, target.z, this.speedModifier); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch index b1cd473fdd52..abbf20097618 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch @@ -9,11 +9,11 @@ this.targetMob = this.mob.getTarget(); this.timestamp = this.mob.getLastHurtByMobTimestamp(); this.unseenMemoryTicks = 300; -@@ -113,6 +_,6 @@ +@@ -111,6 +_,6 @@ } - protected void alertOther(Mob mob, LivingEntity target) { -- mob.setTarget(target); -+ mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason + protected void alertOther(final Mob other, final LivingEntity hurtByMob) { +- other.setTarget(hurtByMob); ++ other.setTarget(hurtByMob, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY); // CraftBukkit - reason } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java.patch index d2987e4f20d7..f5d40856a48e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -@@ -72,7 +_,7 @@ +@@ -77,7 +_,7 @@ @Override public void start() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/gossip/GossipContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/gossip/GossipContainer.java.patch index 72a27d8f56e0..439d8c745b94 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/gossip/GossipContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/gossip/GossipContainer.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java +++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java -@@ -220,6 +_,44 @@ - public void remove(GossipType gossipType) { - this.entries.removeInt(gossipType); +@@ -215,6 +_,44 @@ + public void remove(final GossipType type) { + this.entries.removeInt(type); } + + // Paper start - Add villager reputation API @@ -44,4 +44,4 @@ + // Paper end - Add villager reputation API } - record GossipEntry(UUID target, GossipType type, int value) { + private record GossipEntry(UUID target, GossipType type, int value) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java.patch index d9d5d3eea556..35cafdc37eca 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java.patch @@ -3,9 +3,9 @@ @@ -38,7 +_,7 @@ @Override - public Path createPath(Entity entity, int reachRange) { -- return this.createPath(entity.blockPosition(), reachRange); -+ return this.createPath(entity.blockPosition(), entity, reachRange); // Paper - EntityPathfindEvent + public Path createPath(final Entity target, final int reachRange) { +- return this.createPath(target.blockPosition(), reachRange); ++ return this.createPath(target.blockPosition(), target, reachRange); // Paper - EntityPathfindEvent } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch index 1d1a8daaa97a..690e75c20979 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch @@ -4,13 +4,13 @@ } @Override -- public Path createPath(BlockPos pos, int reachRange) { -+ public Path createPath(BlockPos pos, @javax.annotation.Nullable Entity entity, int reachRange) { // Paper - EntityPathfindEvent - LevelChunk chunkNow = this.level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); - if (chunkNow == null) { +- public Path createPath(BlockPos pos, final int reachRange) { ++ public Path createPath(BlockPos pos, @org.jspecify.annotations.Nullable Entity entity, final int reachRange) { // Paper - EntityPathfindEvent + LevelChunk chunk = this.level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + if (chunk == null) { return null; @@ -51,7 +_,7 @@ - pos = this.findSurfacePosition(chunkNow, pos, reachRange); + pos = this.findSurfacePosition(chunk, pos, reachRange); } - return super.createPath(pos, reachRange); @@ -21,9 +21,9 @@ @@ -91,7 +_,7 @@ @Override - public Path createPath(Entity entity, int reachRange) { -- return this.createPath(entity.blockPosition(), reachRange); -+ return this.createPath(entity.blockPosition(), entity, reachRange); // Paper - EntityPathfindEvent + public Path createPath(final Entity target, final int reachRange) { +- return this.createPath(target.blockPosition(), reachRange); ++ return this.createPath(target.blockPosition(), target, reachRange); // Paper - EntityPathfindEvent } private int getSurfaceY() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch index 788c01d186c7..eabd006e9a8a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch @@ -1,41 +1,41 @@ --- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java -@@ -124,7 +_,12 @@ +@@ -122,7 +_,12 @@ } - public @Nullable Path createPath(BlockPos pos, int reachRange) { + public @Nullable Path createPath(final BlockPos pos, final int reachRange) { - return this.createPath(ImmutableSet.of(pos), 8, false, reachRange); + // Paper start - EntityPathfindEvent + return this.createPath(pos, null, reachRange); + } -+ public @Nullable Path createPath(BlockPos target, @Nullable Entity entity, int reachRange) { -+ return this.createPath(ImmutableSet.of(target), entity, 8, false, reachRange); ++ public @Nullable Path createPath(BlockPos pos, @Nullable Entity entity, int reachRange) { ++ return this.createPath(ImmutableSet.of(pos), entity, 8, false, reachRange); + // Paper end - EntityPathfindEvent } - public @Nullable Path createPath(BlockPos pos, int reachRange, int followRange) { -@@ -132,7 +_,7 @@ + public @Nullable Path createPath(final BlockPos pos, final int reachRange, final int maxPathLength) { +@@ -130,7 +_,7 @@ } - public @Nullable Path createPath(Entity entity, int reachRange) { -- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, reachRange); -+ return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, reachRange); // Paper - EntityPathfindEvent + public @Nullable Path createPath(final Entity target, final int reachRange) { +- return this.createPath(ImmutableSet.of(target.blockPosition()), 16, true, reachRange); ++ return this.createPath(ImmutableSet.of(target.blockPosition()), target, 16, true, reachRange); // Paper - EntityPathfindEvent } - protected @Nullable Path createPath(Set targets, int regionOffset, boolean offsetUpward, int reachRange) { + protected @Nullable Path createPath(final Set targets, final int radiusOffset, final boolean above, final int reachRange) { @@ -140,6 +_,16 @@ - } - - protected @Nullable Path createPath(Set targets, int regionOffset, boolean offsetUpward, int reachRange, float followRange) { + protected @Nullable Path createPath( + final Set targets, final int radiusOffset, final boolean above, final int reachRange, final float maxPathLength + ) { + // Paper start - EntityPathfindEvent -+ return this.createPath(targets, null, regionOffset, offsetUpward, reachRange, followRange); ++ return this.createPath(targets, null, radiusOffset, above, reachRange, maxPathLength); + } + -+ protected @Nullable Path createPath(Set targets, @Nullable Entity target, int regionOffset, boolean offsetUpward, int reachRange) { -+ return this.createPath(targets, target, regionOffset, offsetUpward, reachRange, this.getMaxPathLength()); ++ protected @Nullable Path createPath(Set targets, @Nullable Entity target, int radiusOffset, boolean above, int reachRange) { ++ return this.createPath(targets, target, radiusOffset, above, reachRange, this.getMaxPathLength()); + } + -+ protected @Nullable Path createPath(Set targets, @Nullable Entity target, int regionOffset, boolean offsetUpward, int reachRange, float followRange) { ++ protected @Nullable Path createPath(Set targets, @Nullable Entity target, int radiusOffset, boolean above, int reachRange, float maxPathLength) { + // Paper end - EntityPathfindEvent if (targets.isEmpty()) { return null; @@ -61,10 +61,10 @@ + } + } + // Paper end - EntityPathfindEvent - ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("pathfind"); - BlockPos blockPos = offsetUpward ? this.mob.blockPosition().above() : this.mob.blockPosition(); -@@ -166,6 +_,11 @@ + ProfilerFiller profiler = Profiler.get(); + profiler.push("pathfind"); + BlockPos fromPos = above ? this.mob.blockPosition().above() : this.mob.blockPosition(); +@@ -168,6 +_,11 @@ } } @@ -73,22 +73,22 @@ + private int pathfindFailures = 0; + // Paper end - Perf: Optimise pathfinding + - public boolean moveTo(double x, double y, double z, double speedModifier) { + public boolean moveTo(final double x, final double y, final double z, final double speedModifier) { return this.moveTo(this.createPath(x, y, z, 1), speedModifier); } -@@ -175,8 +_,23 @@ +@@ -177,8 +_,23 @@ } - public boolean moveTo(Entity entity, double speedModifier) { + public boolean moveTo(final Entity target, final double speedModifier) { + // Paper start - Perf: Optimise pathfinding + if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) { + return false; + } + // Paper end - Perf: Optimise pathfinding - Path path = this.createPath(entity, 1); -- return path != null && this.moveTo(path, speedModifier); + Path newPath = this.createPath(target, 1); +- return newPath != null && this.moveTo(newPath, speedModifier); + // Paper start - Perf: Optimise pathfinding -+ if (path != null && this.moveTo(path, speedModifier)) { ++ if (newPath != null && this.moveTo(newPath, speedModifier)) { + this.lastFailure = 0; + this.pathfindFailures = 0; + return true; @@ -100,4 +100,4 @@ + // Paper end - Perf: Optimise pathfinding } - public boolean moveTo(@Nullable Path path, double speedModifier) { + public boolean moveTo(final @Nullable Path newPath, final double speedModifier) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java.patch index 470cc35f4485..7b8011ca7c7a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java.patch @@ -4,8 +4,8 @@ } @Override -- public Path createPath(BlockPos pos, int reachRange) { -+ public Path createPath(BlockPos pos, @Nullable Entity entity, int reachRange) { +- public Path createPath(final BlockPos pos, final int reachRange) { ++ public Path createPath(final BlockPos pos, @Nullable Entity entity, final int reachRange) { this.pathToPosition = pos; - return super.createPath(pos, reachRange); + return super.createPath(pos, entity, reachRange); // Paper - EntityPathfindEvent diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/Sensor.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/Sensor.java.patch index c74a750263fa..bdbf026b80ab 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/Sensor.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/Sensor.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/ai/sensing/Sensor.java +++ b/net/minecraft/world/entity/ai/sensing/Sensor.java -@@ -29,8 +_,17 @@ +@@ -28,8 +_,17 @@ .ignoreInvisibilityTesting(); private final int scanRate; private long timeToTick; + private final String configKey; // Paper - configurable sensor tick rate and timings - public Sensor(int scanRate) { + public Sensor(final int scanRate) { + // Paper start - configurable sensor tick rate and timings -+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName(); ++ String key = this.getClass().getName(); + int lastSeparator = key.lastIndexOf('.'); + if (lastSeparator != -1) { + key = key.substring(lastSeparator + 1); @@ -16,14 +16,14 @@ + this.configKey = key.toLowerCase(java.util.Locale.ROOT); + // Paper end this.scanRate = scanRate; - this.timeToTick = RANDOM.nextInt(scanRate); } -@@ -41,7 +_,7 @@ - public final void tick(ServerLevel level, E entity) { +@@ -43,7 +_,7 @@ + + public final void tick(final ServerLevel level, final E body) { if (--this.timeToTick <= 0L) { - this.timeToTick = this.scanRate; -+ this.timeToTick = java.util.Objects.requireNonNullElse(level.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate); // Paper - configurable sensor tick rate and timings - this.updateTargetingConditionRanges(entity); - this.doTick(level, entity); ++ this.timeToTick = java.util.Objects.requireNonNullElse(level.paperConfig().tickRates.sensor.get(body.getType(), this.configKey), this.scanRate); // Paper - configurable sensor tick rate and timings + this.updateTargetingConditionRanges(body); + this.doTick(level, body); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/TemptingSensor.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/TemptingSensor.java.patch index ac8b07e679f5..67840e2b1193 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/TemptingSensor.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/sensing/TemptingSensor.java.patch @@ -2,12 +2,12 @@ +++ b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java @@ -48,7 +_,19 @@ .collect(Collectors.toList()); - if (!list.isEmpty()) { - Player player = list.get(0); + if (!players.isEmpty()) { + Player player = players.get(0); - brain.setMemory(MemoryModuleType.TEMPTING_PLAYER, player); + // CraftBukkit start + org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent( -+ entity, player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT ++ body, player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT + ); + if (event.isCancelled()) { + return; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch index 5d20e026f9ab..c4ded0a08a6a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/ai/village/VillageSiege.java +++ b/net/minecraft/world/entity/ai/village/VillageSiege.java -@@ -95,11 +_,12 @@ +@@ -102,11 +_,12 @@ zombie.finalizeSpawn(level, level.getCurrentDifficultyAt(zombie.blockPosition()), EntitySpawnReason.EVENT, null); } catch (Exception var5) { - LOGGER.warn("Failed to create zombie for village siege at {}", vec3, var5); + LOGGER.warn("Failed to create zombie for village siege at {}", spawnPos, var5); + com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var5); // Paper - ServerExceptionEvent return; } - zombie.snapTo(vec3.x, vec3.y, vec3.z, level.random.nextFloat() * 360.0F, 0.0F); + zombie.snapTo(spawnPos.x, spawnPos.y, spawnPos.z, level.getRandom().nextFloat() * 360.0F, 0.0F); - level.addFreshEntityWithPassengers(zombie); + level.addFreshEntityWithPassengers(zombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch index 43f464a614ba..78d43b3d6a2a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch @@ -17,25 +17,25 @@ + if (level.getNearestPlayer(BAT_RESTING_TARGETING, this) != null && org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent this.setResting(false); if (!isSilent) { - level.levelEvent(null, LevelEvent.SOUND_BAT_LIFTOFF, blockPos, 0); + level.levelEvent(null, LevelEvent.SOUND_BAT_LIFTOFF, pos, 0); } } - } else { + } else if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent this.setResting(false); if (!isSilent) { - level.levelEvent(null, LevelEvent.SOUND_BAT_LIFTOFF, blockPos, 0); -@@ -177,7 +_,7 @@ - float f1 = Mth.wrapDegrees(f - this.getYRot()); + level.levelEvent(null, LevelEvent.SOUND_BAT_LIFTOFF, pos, 0); +@@ -175,7 +_,7 @@ + float rotDiff = Mth.wrapDegrees(yRotD - this.getYRot()); this.zza = 0.5F; - this.setYRot(this.getYRot() + f1); -- if (this.random.nextInt(100) == 0 && level.getBlockState(blockPos1).isRedstoneConductor(level, blockPos1)) { -+ if (this.random.nextInt(100) == 0 && level.getBlockState(blockPos1).isRedstoneConductor(level, blockPos1) && org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, false)) { // CraftBukkit - Call BatToggleSleepEvent + this.setYRot(this.getYRot() + rotDiff); +- if (this.random.nextInt(100) == 0 && level.getBlockState(above).isRedstoneConductor(level, above)) { ++ if (this.random.nextInt(100) == 0 && level.getBlockState(above).isRedstoneConductor(level, above) && org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, false)) { // CraftBukkit - Call BatToggleSleepEvent this.setResting(true); } } -@@ -202,7 +_,7 @@ - if (this.isInvulnerableTo(level, damageSource)) { +@@ -200,7 +_,7 @@ + if (this.isInvulnerableTo(level, source)) { return false; } else { - if (this.isResting()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/AgeableWaterCreature.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/AgeableWaterCreature.java.patch index a88fad2a6164..fa39b973453d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/AgeableWaterCreature.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/AgeableWaterCreature.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/entity/animal/AgeableWaterCreature.java +++ b/net/minecraft/world/entity/animal/AgeableWaterCreature.java -@@ -68,6 +_,10 @@ +@@ -72,6 +_,10 @@ ) { int seaLevel = level.getSeaLevel(); - int i = seaLevel - 13; + int minSpawnLevel = seaLevel - 13; + // Paper start - Make water animal spawn height configurable + seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel); -+ i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i); ++ minSpawnLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(minSpawnLevel); + // Paper end - Make water animal spawn height configurable - return pos.getY() >= i + return pos.getY() >= minSpawnLevel && pos.getY() <= seaLevel && level.getFluidState(pos.below()).is(FluidTags.WATER) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch index 2fea692e7ee6..9d09a0a9ef99 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch @@ -6,30 +6,30 @@ public @Nullable EntityReference loveCause; + public @Nullable ItemStack breedItem; // CraftBukkit - Add breedItem variable - protected Animal(EntityType type, Level level) { + protected Animal(final EntityType type, final Level level) { super(type, level); @@ -84,9 +_,13 @@ } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg) { + // CraftBukkit start - void -> boolean -+ public boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { -+ boolean damageResult = super.actuallyHurt(level, damageSource, amount, event); ++ public boolean actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg, final org.bukkit.event.entity.EntityDamageEvent event) { ++ boolean damageResult = super.actuallyHurt(level, source, dmg, event); + if (!damageResult) return false; this.resetLove(); -- super.actuallyHurt(level, damageSource, amount); +- super.actuallyHurt(level, source, dmg); + return true; + // CraftBukkit end } @Override @@ -142,8 +_,9 @@ - if (this.isFood(itemInHand)) { + if (this.isFood(itemStack)) { int age = this.getAge(); if (player instanceof ServerPlayer serverPlayer && age == 0 && this.canFallInLove()) { -+ final ItemStack breedCopy = itemInHand.copy(); // Paper - Fix EntityBreedEvent copying - this.usePlayerItem(player, hand, itemInHand); ++ final ItemStack breedCopy = itemStack.copy(); // Paper - Fix EntityBreedEvent copying + this.usePlayerItem(player, hand, itemStack); - this.setInLove(serverPlayer); + this.setInLove(serverPlayer, breedCopy); // Paper - Fix EntityBreedEvent copying this.playEatingSound(); @@ -40,13 +40,13 @@ } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Fix EntityBreedEvent copying - public void setInLove(@Nullable Player player) { + public void setInLove(final @Nullable Player player) { - this.inLove = 600; + // Paper start - Fix EntityBreedEvent copying + this.setInLove(player, null); + } + -+ public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) { ++ public void setInLove(final @Nullable Player player, final @Nullable ItemStack breedItemCopy) { + if (breedItemCopy != null) this.breedItem = breedItemCopy; + // Paper end - Fix EntityBreedEvent copying + // CraftBukkit start @@ -61,15 +61,15 @@ this.loveCause = EntityReference.of(serverPlayer); } @@ -208,23 +_,45 @@ - if (breedOffspring != null) { - breedOffspring.setBaby(true); - breedOffspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); -- this.finalizeSpawnChildFromBreeding(level, partner, breedOffspring); -- level.addFreshEntityWithPassengers(breedOffspring); + if (offspring != null) { + offspring.setBaby(true); + offspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); +- this.finalizeSpawnChildFromBreeding(level, partner, offspring); +- level.addFreshEntityWithPassengers(offspring); + // CraftBukkit start - Call EntityBreedEvent + ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(partner.getLoveCause())).orElse(null); + int experience = this.getRandom().nextInt(7) + 1; -+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, this, partner, breeder, this.breedItem, experience); ++ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(offspring, this, partner, breeder, this.breedItem, experience); + if (entityBreedEvent.isCancelled()) { + this.resetLove(); + partner.resetLove(); @@ -77,38 +77,40 @@ + } + experience = entityBreedEvent.getExperience(); + -+ this.finalizeSpawnChildFromBreeding(level, partner, breedOffspring, experience); -+ level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); ++ this.finalizeSpawnChildFromBreeding(level, partner, offspring, experience); ++ level.addFreshEntityWithPassengers(offspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); + // CraftBukkit end - Call EntityBreedEvent } } - public void finalizeSpawnChildFromBreeding(ServerLevel level, Animal animal, @Nullable AgeableMob baby) { -- Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(animal.getLoveCause())).ifPresent(player -> { + public void finalizeSpawnChildFromBreeding(final ServerLevel level, final Animal partner, final @Nullable AgeableMob offspring) { +- Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(partner.getLoveCause())).ifPresent(cause -> { +- cause.awardStat(Stats.ANIMALS_BRED); +- CriteriaTriggers.BRED_ANIMALS.trigger(cause, this, partner, offspring); +- }); + // CraftBukkit start - Call EntityBreedEvent -+ this.finalizeSpawnChildFromBreeding(level, animal, baby, this.getRandom().nextInt(7) + 1); ++ this.finalizeSpawnChildFromBreeding(level, partner, offspring, this.getRandom().nextInt(7) + 1); + } + -+ public void finalizeSpawnChildFromBreeding(ServerLevel level, Animal animal, @Nullable AgeableMob baby, int experience) { ++ public void finalizeSpawnChildFromBreeding(final ServerLevel level, final Animal partner, final @Nullable AgeableMob offspring, final int experience) { + // CraftBukkit end - Call EntityBreedEvent + // Paper start - Call EntityBreedEvent + ServerPlayer player = this.getLoveCause(); -+ if (player == null) player = animal.getLoveCause(); ++ if (player == null) player = partner.getLoveCause(); + if (player != null) { + // Paper end - Call EntityBreedEvent - player.awardStat(Stats.ANIMALS_BRED); - CriteriaTriggers.BRED_ANIMALS.trigger(player, this, animal, baby); -- }); ++ player.awardStat(Stats.ANIMALS_BRED); ++ CriteriaTriggers.BRED_ANIMALS.trigger(player, this, partner, offspring); + } // Paper - Call EntityBreedEvent this.setAge(6000); - animal.setAge(6000); + partner.setAge(6000); this.resetLove(); - animal.resetLove(); + partner.resetLove(); level.broadcastEntityEvent(this, EntityEvent.IN_LOVE_HEARTS); - if (level.getGameRules().get(GameRules.MOB_DROPS)) { - level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1)); + if (experience > 0 && level.getGameRules().get(GameRules.MOB_DROPS)) { // Paper - Call EntityBreedEvent -+ level.addFreshEntity(new ExperienceOrb(level, this.position(), net.minecraft.world.phys.Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, baby)); // Paper - Call EntityBreedEvent, add spawn context ++ level.addFreshEntity(new ExperienceOrb(level, this.position(), Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, offspring)); // Paper - Call EntityBreedEvent, add spawn context } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch index ffc51bd9ef2d..09872335226f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Bucketable.java.patch @@ -1,38 +1,38 @@ --- a/net/minecraft/world/entity/animal/Bucketable.java +++ b/net/minecraft/world/entity/animal/Bucketable.java -@@ -71,9 +_,25 @@ - static Optional bucketMobPickup(Player player, InteractionHand hand, T entity) { - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.getItem() == Items.WATER_BUCKET && entity.isAlive()) { -- entity.playSound(entity.getPickupSound(), 1.0F, 1.0F); +@@ -73,9 +_,25 @@ + ) { + ItemStack itemStack = player.getItemInHand(hand); + if (itemStack.getItem() == Items.WATER_BUCKET && pickupEntity.isAlive()) { +- pickupEntity.playSound(pickupEntity.getPickupSound(), 1.0F, 1.0F); + // CraftBukkit start -+ // entity.playSound(entity.getPickupSound(), 1.0F, 1.0F); // CraftBukkit - moved down - ItemStack bucketItemStack = entity.getBucketItemStack(); - entity.saveToBucketTag(bucketItemStack); -+ org.bukkit.event.player.PlayerBucketEntityEvent playerBucketFishEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFishBucketEvent(entity, player, itemInHand, bucketItemStack, hand); -+ bucketItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket()); ++ // pickupEntity.playSound(pickupEntity.getPickupSound(), 1.0F, 1.0F); // CraftBukkit - moved down + ItemStack bucket = pickupEntity.getBucketItemStack(); + pickupEntity.saveToBucketTag(bucket); ++ org.bukkit.event.player.PlayerBucketEntityEvent playerBucketFishEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFishBucketEvent(pickupEntity, player, itemStack, bucket, hand); ++ bucket = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket()); + if (playerBucketFishEvent.isCancelled()) { + // Paper start - Fix inventory desync -+ if (player.hasInfiniteMaterials() || itemInHand.getCount() > 1) { ++ if (player.hasInfiniteMaterials() || itemStack.getCount() > 1) { + player.containerMenu.sendAllDataToRemote(); + } else { + player.containerMenu.forceHeldSlot(hand); + } + // Paper end - Fix inventory desync -+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper ++ pickupEntity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper + return Optional.of(InteractionResult.FAIL); + } -+ entity.playSound(entity.getPickupSound(), 1.0F, 1.0F); ++ pickupEntity.playSound(pickupEntity.getPickupSound(), 1.0F, 1.0F); + // CraftBukkit end - ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, bucketItemStack, false); - player.setItemInHand(hand, itemStack); - Level level = entity.level(); -@@ -81,7 +_,7 @@ - CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, bucketItemStack); + ItemStack result = ItemUtils.createFilledResult(itemStack, player, bucket, false); + player.setItemInHand(hand, result); + Level level = pickupEntity.level(); +@@ -83,7 +_,7 @@ + CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, bucket); } -- entity.discard(); -+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause +- pickupEntity.discard(); ++ pickupEntity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause return Optional.of(InteractionResult.SUCCESS); } else { return Optional.empty(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch index ec19e8dbe40e..6bff6c78716a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/allay/Allay.java +++ b/net/minecraft/world/entity/animal/allay/Allay.java -@@ -112,6 +_,7 @@ +@@ -99,6 +_,7 @@ private float dancingAnimationTicks; private float spinningAnimationTicks; private float spinningAnimationTicks0; + public boolean forceDancing = false; // CraftBukkit - public Allay(EntityType type, Level level) { + public Allay(final EntityType type, final Level level) { super(type, level); -@@ -125,6 +_,12 @@ +@@ -112,6 +_,12 @@ ); } @@ -19,9 +19,9 @@ + // CraftBukkit end + @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -@@ -232,7 +_,7 @@ + protected Brain makeBrain(final Brain.Packed packedBrain) { + return BRAIN_PROVIDER.makeBrain(this, packedBrain); +@@ -214,7 +_,7 @@ public void aiStep() { super.aiStep(); if (!this.level().isClientSide() && this.isAlive() && this.tickCount % 10 == 0) { @@ -30,10 +30,10 @@ } if (this.isDancing() && this.shouldStopDancing() && this.tickCount % 20 == 0) { -@@ -300,7 +_,12 @@ - ItemStack itemInHand = player.getItemInHand(hand); - ItemStack itemInHand1 = this.getItemInHand(InteractionHand.MAIN_HAND); - if (this.isDancing() && itemInHand.is(ItemTags.DUPLICATES_ALLAYS) && this.canDuplicate()) { +@@ -282,7 +_,12 @@ + ItemStack interactionItem = player.getItemInHand(hand); + ItemStack itemInHand = this.getItemInHand(InteractionHand.MAIN_HAND); + if (this.isDancing() && interactionItem.is(ItemTags.DUPLICATES_ALLAYS) && this.canDuplicate()) { - this.duplicateAllay(); + // CraftBukkit start - handle cancel duplication + Allay allay = this.duplicateAllay(); @@ -43,8 +43,8 @@ + // CraftBukkit end this.level().broadcastEntityEvent(this, EntityEvent.IN_LOVE_HEARTS); this.level().playSound(player, this, SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.NEUTRAL, 2.0F, 1.0F); - this.removeInteractionItem(player, itemInHand); -@@ -399,6 +_,7 @@ + this.removeInteractionItem(player, interactionItem); +@@ -381,6 +_,7 @@ } private boolean shouldStopDancing() { @@ -52,7 +52,7 @@ return this.jukeboxPos == null || !this.jukeboxPos.closerToCenterThan(this.position(), GameEvent.JUKEBOX_PLAY.value().notificationRadius()) || !this.level().getBlockState(this.jukeboxPos).is(Blocks.JUKEBOX); -@@ -451,7 +_,7 @@ +@@ -433,7 +_,7 @@ super.readAdditionalSaveData(input); this.readInventoryFromTag(input); this.vibrationData = input.read("listener", VibrationSystem.Data.CODEC).orElseGet(VibrationSystem.Data::new); @@ -61,7 +61,7 @@ } @Override -@@ -470,15 +_,17 @@ +@@ -452,15 +_,17 @@ this.entityData.set(DATA_CAN_DUPLICATE, duplicationCooldown == 0L); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch index 81ee48b69608..77e4f5dc38d0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java +++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java -@@ -137,10 +_,12 @@ +@@ -145,10 +_,12 @@ ArmadilloAi.updateActivity(this); - profilerFiller.pop(); + profiler.pop(); if (this.isAlive() && --this.scuteTime <= 0 && this.shouldDropLoot(level)) { + this.forceDrops = true; // CraftBukkit if (this.dropFromGiftLootTable(level, BuiltInLootTables.ARMADILLO_SHED, this::spawnAtLocation)) { @@ -13,21 +13,21 @@ this.scuteTime = this.pickNextScuteDropTime(); } -@@ -277,8 +_,11 @@ +@@ -285,8 +_,11 @@ } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { -- super.actuallyHurt(level, damageSource, amount); +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg) { +- super.actuallyHurt(level, source, dmg); + // CraftBukkit start - void -> boolean -+ public boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { -+ boolean damageResult = super.actuallyHurt(level, damageSource, amount, event); ++ public boolean actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg, org.bukkit.event.entity.EntityDamageEvent event) { ++ boolean damageResult = super.actuallyHurt(level, source, dmg, event); + if (!damageResult) return false; + // CraftBukkit end if (!this.isNoAi() && !this.isDeadOrDying()) { - if (damageSource.getEntity() instanceof LivingEntity) { + if (source.getEntity() instanceof LivingEntity) { this.getBrain().setMemoryWithExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY, true, 80L); -@@ -289,6 +_,7 @@ +@@ -297,6 +_,7 @@ this.rollOut(); } } @@ -35,12 +35,12 @@ } @Override -@@ -307,7 +_,9 @@ +@@ -315,7 +_,9 @@ return false; } else { - if (this.level() instanceof ServerLevel serverLevel) { + if (this.level() instanceof ServerLevel level) { + this.forceDrops = true; // CraftBukkit - this.dropFromEntityInteractLootTable(serverLevel, BuiltInLootTables.ARMADILLO_BRUSH, entity, stack, this::spawnAtLocation); + this.dropFromEntityInteractLootTable(level, BuiltInLootTables.ARMADILLO_BRUSH, interactingEntity, tool, this::spawnAtLocation); + this.forceDrops = false; // CraftBukkit this.playSound(SoundEvents.ARMADILLO_BRUSH); this.gameEvent(GameEvent.ENTITY_INTERACT); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch index db1f768482cf..4b25ea0df6ad 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -232,7 +_,7 @@ +@@ -270,7 +_,7 @@ @Override public int getMaxAirSupply() { @@ -9,12 +9,12 @@ } public Axolotl.Variant getVariant() { -@@ -448,10 +_,10 @@ - if (effect == null || effect.endsWithin(2399)) { - int i = effect != null ? effect.getDuration() : 0; - int min = Math.min(2400, 100 + i); -- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 0), this); -+ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit +@@ -484,10 +_,10 @@ + if (regenEffect == null || regenEffect.endsWithin(2399)) { + int previousDuration = regenEffect != null ? regenEffect.getDuration() : 0; + int regenDuration = Math.min(2400, 100 + previousDuration); +- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, regenDuration, 0), this); ++ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, regenDuration, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit } - player.removeEffect(MobEffects.MINING_FATIGUE); @@ -22,7 +22,7 @@ } @Override -@@ -530,6 +_,13 @@ +@@ -565,6 +_,13 @@ ) { return level.getBlockState(pos.below()).is(BlockTags.AXOLOTLS_SPAWNABLE_ON); } @@ -34,5 +34,5 @@ + } + // CraftBukkit end - public static enum AnimationState { - PLAYING_DEAD, + @Override + public EntityDimensions getDefaultDimensions(final Pose pose) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch index f215390a758b..9764afc7614d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/animal/bee/Bee.java +++ b/net/minecraft/world/entity/animal/bee/Bee.java -@@ -149,10 +_,26 @@ - Bee.BeeGoToHiveGoal goToHiveGoal; +@@ -150,10 +_,26 @@ + private Bee.BeeGoToHiveGoal goToHiveGoal; private Bee.BeeGoToKnownFlowerGoal goToKnownFlowerGoal; private int underWaterTicks; + public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override - public Bee(EntityType type, Level level) { + public Bee(final EntityType type, final Level level) { super(type, level); - this.moveControl = new FlyingMoveControl(this, 20, true); + // Paper start - Fix MC-167279 @@ -26,18 +26,18 @@ + this.moveControl = new BeeFlyingMoveControl(this, 20, true); + // Paper end - Fix MC-167279 this.lookControl = new Bee.BeeLookControl(this); - this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); + this.setPathfindingMalus(PathType.FIRE_IN_NEIGHBOR, -1.0F); this.setPathfindingMalus(PathType.WATER, -1.0F); -@@ -199,9 +_,18 @@ +@@ -200,9 +_,18 @@ @Override - protected void addAdditionalSaveData(ValueOutput output) { + protected void addAdditionalSaveData(final ValueOutput output) { + // CraftBukkit start - selectively save data + this.addAdditionalSaveData(output, true); + } + + @Override -+ public void addAdditionalSaveData(ValueOutput output, boolean saveAll) { ++ public void addAdditionalSaveData(final ValueOutput output, final boolean saveAll) { + // CraftBukkit end super.addAdditionalSaveData(output); + if (saveAll) { // Paper @@ -47,16 +47,16 @@ output.putBoolean("HasNectar", this.hasNectar()); output.putBoolean("HasStung", this.hasStung()); output.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive); -@@ -239,7 +_,7 @@ +@@ -240,7 +_,7 @@ } - if (i > 0) { -- livingEntity.addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this); -+ livingEntity.addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + if (poisonTime > 0) { +- livingTarget.addEffect(new MobEffectInstance(MobEffects.POISON, poisonTime * 20, 0), this); ++ livingTarget.addEffect(new MobEffectInstance(MobEffects.POISON, poisonTime * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } -@@ -480,7 +_,11 @@ +@@ -483,7 +_,11 @@ if (this.hivePos == null) { return null; } else { @@ -69,58 +69,60 @@ } } -@@ -513,6 +_,7 @@ +@@ -515,7 +_,8 @@ + return this.getFlag(FLAG_ROLL); } - public void setRolling(boolean isRolling) { -+ isRolling = this.rollingOverride.toBooleanOrElse(isRolling); // Paper - Rolling override - this.setFlag(FLAG_ROLL, isRolling); +- public void setRolling(final boolean rolling) { ++ public void setRolling(boolean rolling) { // Paper - Rolling override ++ rolling = this.rollingOverride.toBooleanOrElse(rolling); // Paper - Rolling override + this.setFlag(FLAG_ROLL, rolling); } -@@ -569,7 +_,7 @@ - if (beeInteractionEffect != null) { - this.usePlayerItem(player, hand, itemInHand); +@@ -576,7 +_,7 @@ + if (effect != null) { + this.usePlayerItem(player, hand, heldItem); if (!this.level().isClientSide()) { -- this.addEffect(beeInteractionEffect); -+ this.addEffect(beeInteractionEffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause +- this.addEffect(effect); ++ this.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause } return InteractionResult.SUCCESS; -@@ -637,8 +_,9 @@ - if (this.isInvulnerableTo(level, damageSource)) { +@@ -644,8 +_,9 @@ + if (this.isInvulnerableTo(level, source)) { return false; } else { -+ if (!super.hurtServer(level, damageSource, amount)) return false; // CraftBukkit - Only stop pollinating if entity was damaged ++ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit - Only stop pollinating if entity was damaged this.beePollinateGoal.stopPollinating(); -- return super.hurtServer(level, damageSource, amount); +- return super.hurtServer(level, source, damage); + return true; // CraftBukkit - Only stop pollinating if entity was damaged } } -@@ -979,7 +_,7 @@ +@@ -1007,7 +_,7 @@ } } -- if (blockState1 != null) { -+ if (blockState1 != null && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Bee.this, blockPos, blockState1)) { // CraftBukkit - Bee.this.level().levelEvent(LevelEvent.PARTICLES_BEE_GROWTH, blockPos, 15); - Bee.this.level().setBlockAndUpdate(blockPos, blockState1); +- if (growState != null) { ++ if (growState != null && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Bee.this, belowPos, growState)) { // CraftBukkit + Bee.this.level().levelEvent(LevelEvent.PARTICLES_BEE_GROWTH, belowPos, 15); + Bee.this.level().setBlockAndUpdate(belowPos, growState); Bee.this.incrementNumCropsGrownSincePollination(); -@@ -1003,7 +_,7 @@ +@@ -1032,7 +_,7 @@ @Override - protected void alertOther(Mob mob, LivingEntity target) { - if (mob instanceof Bee && this.mob.hasLineOfSight(target)) { -- mob.setTarget(target); -+ mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); // CraftBukkit - reason + protected void alertOther(final Mob other, final LivingEntity hurtByMob) { + if (other instanceof Bee && this.mob.hasLineOfSight(hurtByMob)) { +- other.setTarget(hurtByMob); ++ other.setTarget(hurtByMob, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); // CraftBukkit - reason } } } -@@ -1160,7 +_,7 @@ +@@ -1198,7 +_,7 @@ Bee.this.dropFlower(); this.pollinating = false; Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; - } else { + } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this - Vec3 vec3 = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0, 0.6F, 0.0); - if (vec3.distanceTo(Bee.this.position()) > 1.0) { - this.hoverPos = vec3; + Vec3 flowerPos = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0, 0.6F, 0.0); + if (flowerPos.distanceTo(Bee.this.position()) > 1.0) { + this.hoverPos = flowerPos; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch index 39caee1ceda0..1514f5e2c95c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch @@ -1,37 +1,37 @@ --- a/net/minecraft/world/entity/animal/camel/Camel.java +++ b/net/minecraft/world/entity/animal/camel/Camel.java -@@ -411,12 +_,12 @@ +@@ -419,12 +_,12 @@ } else { - boolean flag = this.getHealth() < this.getMaxHealth(); - if (flag) { + boolean couldHeal = this.getHealth() < this.getMaxHealth(); + if (couldHeal) { - this.heal(2.0F); + this.heal(2.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason } - boolean flag1 = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); - if (flag1) { + boolean couldSetInLove = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); + if (couldSetInLove) { - this.setInLove(player); -+ this.setInLove(player, stack.copy()); // Paper - Fix EntityBreedEvent copying ++ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying } - boolean isBaby = this.isBaby(); -@@ -474,9 +_,13 @@ + boolean couldAgeUp = this.canAgeUp(); +@@ -482,9 +_,13 @@ } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg) { + // CraftBukkit start - void -> boolean -+ public boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { -+ boolean damageResult = super.actuallyHurt(level, damageSource, amount, event); ++ public boolean actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg, final org.bukkit.event.entity.EntityDamageEvent event) { ++ boolean damageResult = super.actuallyHurt(level, source, dmg, event); + if (!damageResult) return false; + // CraftBukkit end this.standUpInstantly(); -- super.actuallyHurt(level, damageSource, amount); +- super.actuallyHurt(level, source, dmg); + return true; // CraftBukkit } @Override -@@ -571,7 +_,7 @@ +@@ -581,7 +_,7 @@ } public void sitDown() { @@ -40,7 +40,7 @@ this.makeSound(this.getSitDownSound()); this.setPose(Pose.SITTING); this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -580,7 +_,7 @@ +@@ -590,7 +_,7 @@ } public void standUp() { @@ -49,7 +49,7 @@ this.makeSound(this.getStandUpSound()); this.setPose(Pose.STANDING); this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -597,6 +_,7 @@ +@@ -607,6 +_,7 @@ } public void standUpInstantly() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/chicken/Chicken.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/chicken/Chicken.java.patch index b462eb81c29d..87b77809a3cd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/chicken/Chicken.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/chicken/Chicken.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/animal/chicken/Chicken.java +++ b/net/minecraft/world/entity/animal/chicken/Chicken.java -@@ -113,10 +_,12 @@ +@@ -128,10 +_,12 @@ this.flap = this.flap + this.flapping * 2.0F; - if (this.level() instanceof ServerLevel serverLevel && this.isAlive() && !this.isBaby() && !this.isChickenJockey() && --this.eggTime <= 0) { + if (this.level() instanceof ServerLevel level && this.isAlive() && !this.isBaby() && !this.isChickenJockey() && --this.eggTime <= 0) { + this.forceDrops = true; // CraftBukkit - if (this.dropFromGiftLootTable(serverLevel, BuiltInLootTables.CHICKEN_LAY, this::spawnAtLocation)) { + if (this.dropFromGiftLootTable(level, BuiltInLootTables.CHICKEN_LAY, this::spawnAtLocation)) { this.playSound(SoundEvents.CHICKEN_EGG, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); this.gameEvent(GameEvent.ENTITY_PLACE); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch index 396d38adc60d..0d24fa52ee3b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/AbstractCow.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/entity/animal/cow/AbstractCow.java +++ b/net/minecraft/world/entity/animal/cow/AbstractCow.java -@@ -85,8 +_,15 @@ - public InteractionResult mobInteract(Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.is(Items.BUCKET) && !this.isBaby()) { +@@ -89,8 +_,15 @@ + public InteractionResult mobInteract(final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); + if (itemStack.is(Items.BUCKET) && !this.isBaby()) { + // CraftBukkit start - Got milk? -+ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand); ++ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(player.level(), player, this.blockPosition(), this.blockPosition(), null, itemStack, Items.MILK_BUCKET, hand); + if (event.isCancelled()) { + player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.PASS; + } + // CraftBukkit end player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); -- ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, Items.MILK_BUCKET.getDefaultInstance()); -+ ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit - player.setItemInHand(hand, itemStack); +- ItemStack bucketOrMilkBucket = ItemUtils.createFilledResult(itemStack, player, Items.MILK_BUCKET.getDefaultInstance()); ++ ItemStack bucketOrMilkBucket = ItemUtils.createFilledResult(itemStack, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + player.setItemInHand(hand, bucketOrMilkBucket); return InteractionResult.SUCCESS; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch index c0e2f6acbeff..8f0b1d75a5ef 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/cow/MushroomCow.java.patch @@ -2,49 +2,49 @@ +++ b/net/minecraft/world/entity/animal/cow/MushroomCow.java @@ -116,7 +_,17 @@ return InteractionResult.SUCCESS; - } else if (itemInHand.is(Items.SHEARS) && this.readyForShearing()) { - if (this.level() instanceof ServerLevel serverLevel) { -- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); + } else if (itemStack.is(Items.SHEARS) && this.readyForShearing()) { + if (this.level() instanceof ServerLevel level) { +- this.shear(level, SoundSource.PLAYERS, itemStack); + // CraftBukkit start + // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); -+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(level, itemStack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemStack, hand, drops); + if (event != null) { + if (event.isCancelled()) return InteractionResult.PASS; + drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); + // Paper end - custom shear drops + } + // CraftBukkit end -+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); // Paper - custom shear drops ++ this.shear(level, SoundSource.PLAYERS, itemStack, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); - itemInHand.hurtAndBreak(1, player, hand.asEquipmentSlot()); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); } @@ -170,15 +_,31 @@ @Override - public void shear(ServerLevel level, SoundSource source, ItemStack shears) { + public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { + // Paper start - custom shear drops -+ this.shear(level, source, shears, this.generateDefaultDrops(level, shears)); ++ this.shear(level, soundSource, tool, this.generateDefaultDrops(level, tool)); + } + + @Override -+ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack shears) { ++ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (ignored, stack) -> { ++ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_MOOSHROOM, tool, (ignored, stack) -> { + for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); + }); + return drops; + } + + @Override -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool, java.util.List drops) { + // Paper end - level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, source, 1.0F, 1.0F); + level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, soundSource, 1.0F, 1.0F); this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), cow -> { level.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5), this.getZ(), 1, 0.0, 0.0, 0.0, 0.0); -- this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (serverLevel, stack) -> { -- for (int i = 0; i < stack.getCount(); i++) { -- serverLevel.addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0), this.getZ(), stack.copyWithCount(1))); +- this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_MOOSHROOM, tool, (l, drop) -> { +- for (int i = 0; i < drop.getCount(); i++) { +- l.addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0), this.getZ(), drop.copyWithCount(1))); - } + // Paper start - custom shear drops; moved drop generation to separate method + drops.forEach(drop -> { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch index 91bed267dcc2..13396171a0be 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/dolphin/Dolphin.java +++ b/net/minecraft/world/entity/animal/dolphin/Dolphin.java -@@ -98,6 +_,13 @@ +@@ -100,6 +_,13 @@ return EntityType.DOLPHIN.create(level, EntitySpawnReason.BREEDING); } @@ -14,7 +14,7 @@ @Override public float getAgeScale() { return this.isBaby() ? 0.65F : 1.0F; -@@ -182,7 +_,7 @@ +@@ -185,7 +_,7 @@ @Override public int getMaxAirSupply() { @@ -23,24 +23,24 @@ } @Override -@@ -215,11 +_,15 @@ +@@ -218,11 +_,15 @@ if (this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty()) { - ItemStack item = entity.getItem(); - if (this.canHoldItem(item)) { + ItemStack itemStack = entity.getItem(); + if (this.canHoldItem(itemStack)) { + // CraftBukkit start - call EntityPickupItemEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0).isCancelled()) return; -+ item = entity.getItem(); // CraftBukkit- update ItemStack from event ++ itemStack = entity.getItem(); // CraftBukkit- update ItemStack from event + // CraftBukkit end this.onItemPickup(entity); - this.setItemSlot(EquipmentSlot.MAINHAND, item); + this.setItemSlot(EquipmentSlot.MAINHAND, itemStack); this.setGuaranteedDrop(EquipmentSlot.MAINHAND); - this.take(entity, item.getCount()); + this.take(entity, itemStack.getCount()); - entity.discard(); + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } } } -@@ -479,7 +_,7 @@ +@@ -480,7 +_,7 @@ @Override public void start() { @@ -49,21 +49,21 @@ } @Override -@@ -498,7 +_,7 @@ +@@ -499,7 +_,7 @@ } - if (this.player.isSwimming() && this.player.level().random.nextInt(6) == 0) { + if (this.player.isSwimming() && this.player.level().getRandom().nextInt(6) == 0) { - this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin); + this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DOLPHIN); // CraftBukkit } } } -@@ -568,7 +_,7 @@ +@@ -575,7 +_,7 @@ 0.3F * Mth.cos(Dolphin.this.getYRot() * (float) (Math.PI / 180.0)) * Mth.cos(Dolphin.this.getXRot() * (float) (Math.PI / 180.0)) - + Mth.sin(f1) * f2 + + Mth.sin(dir) * pow2 ); -- Dolphin.this.level().addFreshEntity(itemEntity); -+ Dolphin.this.spawnAtLocation(getServerLevel(Dolphin.this), itemEntity); // Paper - Call EntityDropItemEvent +- Dolphin.this.level().addFreshEntity(thrownItem); ++ Dolphin.this.spawnAtLocation(getServerLevel(Dolphin.this), thrownItem); // Paper - Call EntityDropItemEvent } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch index f0d60ff3e63d..5e1eb25224f2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java +++ b/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java -@@ -74,6 +_,12 @@ +@@ -75,6 +_,12 @@ super.dropEquipment(level); if (this.hasChest()) { this.spawnAtLocation(level, Blocks.CHEST); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch index 52883f8e6a3b..73571e79cb8a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/equine/AbstractHorse.java +++ b/net/minecraft/world/entity/animal/equine/AbstractHorse.java -@@ -124,6 +_,7 @@ +@@ -125,6 +_,7 @@ protected boolean canGallop = true; protected int gallopSoundCounter; public @Nullable EntityReference owner; + public int maxDomestication = 100; // CraftBukkit - store max domestication value - protected AbstractHorse(EntityType type, Level level) { + protected AbstractHorse(final EntityType type, final Level level) { super(type, level); -@@ -252,7 +_,7 @@ +@@ -253,7 +_,7 @@ } @Override @@ -17,16 +17,16 @@ return !this.isVehicle(); } -@@ -299,7 +_,7 @@ +@@ -300,7 +_,7 @@ public void createInventory() { - SimpleContainer simpleContainer = this.inventory; + SimpleContainer old = this.inventory; - this.inventory = new SimpleContainer(this.getInventorySize()); + this.inventory = new SimpleContainer(this.getInventorySize(), (org.bukkit.entity.AbstractHorse) this.getBukkitEntity()); // CraftBukkit - if (simpleContainer != null) { - int min = Math.min(simpleContainer.getContainerSize(), this.inventory.getContainerSize()); + if (old != null) { + int max = Math.min(old.getContainerSize(), this.inventory.getContainerSize()); -@@ -391,7 +_,7 @@ +@@ -392,7 +_,7 @@ } public int getMaxTemper() { @@ -35,40 +35,40 @@ } @Override -@@ -454,7 +_,7 @@ - i1 = 5; +@@ -455,7 +_,7 @@ + temper = 5; if (!this.level().isClientSide() && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { - flag = true; + itemUsed = true; - this.setInLove(player); -+ this.setInLove(player, stack.copy()); // Paper - Fix EntityBreedEvent copying ++ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying } - } else if (stack.is(Items.GOLDEN_APPLE) || stack.is(Items.ENCHANTED_GOLDEN_APPLE)) { - f = 10.0F; -@@ -462,12 +_,12 @@ - i1 = 10; + } else if (itemStack.is(Items.GOLDEN_APPLE) || itemStack.is(Items.ENCHANTED_GOLDEN_APPLE)) { + heal = 10.0F; +@@ -463,12 +_,12 @@ + temper = 10; if (!this.level().isClientSide() && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { - flag = true; + itemUsed = true; - this.setInLove(player); -+ this.setInLove(player, stack.copy()); // Paper - Fix EntityBreedEvent copying ++ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying } } - if (this.getHealth() < this.getMaxHealth() && f > 0.0F) { -- this.heal(f); -+ this.heal(f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit - flag = true; + if (this.getHealth() < this.getMaxHealth() && heal > 0.0F) { +- this.heal(heal); ++ this.heal(heal, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit + itemUsed = true; } -@@ -538,7 +_,7 @@ +@@ -539,7 +_,7 @@ super.aiStep(); - if (this.level() instanceof ServerLevel serverLevel && this.isAlive()) { + if (this.level() instanceof ServerLevel level && this.isAlive()) { if (this.random.nextInt(900) == 0 && this.deathTime == 0) { - this.heal(1.0F); + this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit } if (this.canEatGrass()) { -@@ -640,6 +_,16 @@ +@@ -641,6 +_,16 @@ } } @@ -83,9 +83,9 @@ + // Paper end - Horse API + @Override - public InteractionResult mobInteract(Player player, InteractionHand hand) { + public InteractionResult mobInteract(final Player player, final InteractionHand hand) { if (this.isVehicle() || this.isBaby()) { -@@ -791,6 +_,7 @@ +@@ -792,6 +_,7 @@ output.putInt("Temper", this.getTemper()); output.putBoolean("Tame", this.isTamed()); EntityReference.store(this.owner, output, "Owner"); @@ -93,7 +93,7 @@ } @Override -@@ -801,6 +_,7 @@ +@@ -802,6 +_,7 @@ this.setTemper(input.getIntOr("Temper", 0)); this.setTamed(input.getBooleanOr("Tame", false)); this.owner = EntityReference.readWithOldOwnerConversion(input, "Owner", this.level()); @@ -101,16 +101,16 @@ } @Override -@@ -888,6 +_,17 @@ +@@ -895,6 +_,17 @@ @Override - public void handleStartJump(int jumpPower) { + public void handleStartJump(final int jumpScale) { + // CraftBukkit start + float power; -+ if (jumpPower >= 90) { ++ if (jumpScale >= 90) { + power = 1.0F; + } else { -+ power = 0.4F + 0.4F * (float) jumpPower / 90.0F; ++ power = 0.4F + 0.4F * (float) jumpScale / 90.0F; + } + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callHorseJumpEvent(this, power)) { + return; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch index 514774700575..5e819a923671 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/Llama.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/entity/animal/equine/Llama.java +++ b/net/minecraft/world/entity/animal/equine/Llama.java -@@ -75,18 +_,19 @@ +@@ -74,18 +_,19 @@ .scale(0.5F); - boolean didSpit; + private boolean didSpit; private @Nullable Llama caravanHead; - private @Nullable Llama caravanTail; + public @Nullable Llama caravanTail; // Paper - public - public Llama(EntityType type, Level level) { + public Llama(final EntityType type, final Level level) { super(type, level); this.getNavigation().setRequiredPathLength(40.0F); + this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value @@ -17,27 +17,27 @@ return false; } -- private void setStrength(int strength) { -+ public void setStrength(int strength) { // Paper - public +- private void setStrength(final int strength) { ++ public void setStrength(final int strength) { // Paper - public this.entityData.set(DATA_STRENGTH_ID, Math.max(1, Math.min(5, strength))); } -@@ -191,12 +_,12 @@ - f = 10.0F; +@@ -190,12 +_,12 @@ + heal = 10.0F; if (this.isTamed() && this.getAge() == 0 && this.canFallInLove()) { - flag = true; + itemUsed = true; - this.setInLove(player); -+ this.setInLove(player, stack.copy()); // Paper - Fix EntityBreedEvent copying ++ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying } } - if (this.getHealth() < this.getMaxHealth() && f > 0.0F) { -- this.heal(f); -+ this.heal(f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason - flag = true; + if (this.getHealth() < this.getMaxHealth() && heal > 0.0F) { +- this.heal(heal); ++ this.heal(heal, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason + itemUsed = true; } -@@ -308,7 +_,7 @@ +@@ -307,7 +_,7 @@ @Override public int getMaxTemper() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonHorse.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonHorse.java.patch index 43ae42746bd0..528468435da6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonHorse.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonHorse.java.patch @@ -3,7 +3,7 @@ @@ -126,7 +_,7 @@ public void aiStep() { super.aiStep(); - if (this.isTrap() && this.trapTime++ >= 18000) { + if (!this.isPersistenceRequired() && this.isTrap() && this.trapTime++ >= 18000) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonTrapGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonTrapGoal.java.patch index 0017eebc7c21..c908cb39e179 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonTrapGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/SkeletonTrapGoal.java.patch @@ -6,7 +6,7 @@ private final SkeletonHorse horse; + private java.util.List eligiblePlayers; // Paper - public SkeletonTrapGoal(SkeletonHorse horse) { + public SkeletonTrapGoal(final SkeletonHorse horse) { this.horse = horse; @@ -25,12 +_,13 @@ @@ -18,31 +18,31 @@ @Override public void tick() { - ServerLevel serverLevel = (ServerLevel)this.horse.level(); + ServerLevel level = (ServerLevel)this.horse.level(); + if (!new com.destroystokyo.paper.event.entity.SkeletonHorseTrapEvent((org.bukkit.entity.SkeletonHorse) this.horse.getBukkitEntity(), this.eligiblePlayers).callEvent()) return; // Paper - DifficultyInstance currentDifficultyAt = serverLevel.getCurrentDifficultyAt(this.horse.blockPosition()); + DifficultyInstance difficulty = level.getCurrentDifficultyAt(this.horse.blockPosition()); this.horse.setTrap(false); this.horse.setTamed(true); @@ -39,11 +_,11 @@ - if (lightningBolt != null) { - lightningBolt.snapTo(this.horse.getX(), this.horse.getY(), this.horse.getZ()); - lightningBolt.setVisualOnly(true); -- serverLevel.addFreshEntity(lightningBolt); -+ serverLevel.strikeLightning(lightningBolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.TRAP); // CraftBukkit - Skeleton skeleton = this.createSkeleton(currentDifficultyAt, this.horse); + if (bolt != null) { + bolt.snapTo(this.horse.getX(), this.horse.getY(), this.horse.getZ()); + bolt.setVisualOnly(true); +- level.addFreshEntity(bolt); ++ level.strikeLightning(bolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.TRAP); // CraftBukkit + Skeleton skeleton = this.createSkeleton(difficulty, this.horse); if (skeleton != null) { skeleton.startRiding(this.horse); -- serverLevel.addFreshEntityWithPassengers(skeleton); -+ serverLevel.addFreshEntityWithPassengers(skeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRAP); // CraftBukkit +- level.addFreshEntityWithPassengers(skeleton); ++ level.addFreshEntityWithPassengers(skeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRAP); // CraftBukkit for (int i = 0; i < 3; i++) { - AbstractHorse abstractHorse = this.createHorse(currentDifficultyAt); + AbstractHorse otherHorse = this.createHorse(difficulty); @@ -52,7 +_,7 @@ - if (skeleton1 != null) { - skeleton1.startRiding(abstractHorse); - abstractHorse.push(this.horse.getRandom().triangle(0.0, 1.1485), 0.0, this.horse.getRandom().triangle(0.0, 1.1485)); -- serverLevel.addFreshEntityWithPassengers(abstractHorse); -+ serverLevel.addFreshEntityWithPassengers(abstractHorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.JOCKEY); // CraftBukkit + if (otherSkeleton != null) { + otherSkeleton.startRiding(otherHorse); + otherHorse.push(this.horse.getRandom().triangle(0.0, 1.1485), 0.0, this.horse.getRandom().triangle(0.0, 1.1485)); +- level.addFreshEntityWithPassengers(otherHorse); ++ level.addFreshEntityWithPassengers(otherHorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.JOCKEY); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/TraderLlama.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/TraderLlama.java.patch index 6fe1f4c67b78..911be680c2b7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/TraderLlama.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/TraderLlama.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/equine/TraderLlama.java +++ b/net/minecraft/world/entity/animal/equine/TraderLlama.java -@@ -88,7 +_,7 @@ +@@ -92,7 +_,7 @@ this.despawnDelay = this.isLeashedToWanderingTrader() ? ((WanderingTrader)this.getLeashHolder()).getDespawnDelay() - 1 : this.despawnDelay - 1; if (this.despawnDelay <= 0) { this.removeLeash(); @@ -9,7 +9,7 @@ } } } -@@ -146,7 +_,7 @@ +@@ -154,7 +_,7 @@ @Override public void start() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch index 4f297d72d1fb..6c4d55c9a4f7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch @@ -1,49 +1,40 @@ --- a/net/minecraft/world/entity/animal/feline/Cat.java +++ b/net/minecraft/world/entity/animal/feline/Cat.java -@@ -372,6 +_,11 @@ - if (item instanceof DyeItem dyeItem) { - DyeColor dyeColor = dyeItem.getDyeColor(); - if (dyeColor != this.getCollarColor()) { +@@ -400,6 +_,11 @@ + if (itemStack.is(ItemTags.CAT_COLLAR_DYES)) { + DyeColor color = itemStack.get(DataComponents.DYE); + if (color != null && color != this.getCollarColor()) { + // Paper start - Add EntityDyeEvent and CollarColorable interface -+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) dyeColor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity()); ++ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) color.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity()); + if (!event.callEvent()) return InteractionResult.FAIL; -+ dyeColor = DyeColor.byId(event.getColor().getWoolData()); ++ color = DyeColor.byId(event.getColor().getWoolData()); + // Paper end - Add EntityDyeEvent and CollarColorable interface if (!this.level().isClientSide()) { - this.setCollarColor(dyeColor); - itemInHand.consume(1, player); -@@ -384,7 +_,7 @@ - if (!this.level().isClientSide()) { - this.usePlayerItem(player, hand, itemInHand); - FoodProperties foodProperties = itemInHand.get(DataComponents.FOOD); -- this.heal(foodProperties != null ? foodProperties.nutrition() : 1.0F); -+ this.heal(foodProperties != null ? foodProperties.nutrition() : 1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason - this.playEatingSound(); - } - -@@ -446,7 +_,7 @@ + this.setCollarColor(color); + itemStack.consume(1, player); +@@ -471,7 +_,7 @@ } - private void tryToTame(Player player) { + private void tryToTame(final Player player) { - if (this.random.nextInt(3) == 0) { + if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit this.tame(player); this.setOrderedToSit(true); this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED); -@@ -579,15 +_,20 @@ +@@ -601,15 +_,20 @@ .dropFromGiftLootTable( getServerLevel(this.cat), BuiltInLootTables.CAT_MORNING_GIFT, -- (level, stack) -> level.addFreshEntity( +- (level, itemStack) -> level.addFreshEntity( - new ItemEntity( + // CraftBukkit start -+ (level, stack) -> { ++ (level, itemStack) -> { + final ItemEntity item = new ItemEntity( level, - (double)mutableBlockPos.getX() - Mth.sin(this.cat.yBodyRot * (float) (Math.PI / 180.0)), - mutableBlockPos.getY(), - (double)mutableBlockPos.getZ() + Mth.cos(this.cat.yBodyRot * (float) (Math.PI / 180.0)), - stack + (double)catPos.getX() - Mth.sin(this.cat.yBodyRot * (float) (Math.PI / 180.0)), + catPos.getY(), + (double)catPos.getZ() + Mth.cos(this.cat.yBodyRot * (float) (Math.PI / 180.0)), + itemStack - ) - ) + ); @@ -55,12 +46,12 @@ ); } -@@ -613,7 +_,7 @@ +@@ -635,7 +_,7 @@ } - static class CatTemptGoal extends TemptGoal { + private static class CatTemptGoal extends TemptGoal { - private @Nullable Player selectedPlayer; + private @Nullable LivingEntity selectedPlayer; // CraftBukkit private final Cat cat; - public CatTemptGoal(Cat cat, double speedModifier, Predicate items, boolean canScare) { + public CatTemptGoal(final Cat mob, final double speedModifier, final Predicate items, final boolean canScare) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch index 0a20cf90d180..1b4bd7317427 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Ocelot.java.patch @@ -3,15 +3,15 @@ @@ -129,7 +_,7 @@ @Override - public boolean removeWhenFarAway(double distanceToClosestPlayer) { + public boolean removeWhenFarAway(final double distSqr) { - return !this.isTrusting() && this.tickCount > 2400; + return !this.isTrusting() && this.tickCount > 2400 && !this.hasCustomName() && !this.isLeashed(); // Paper - honor name and leash } public static AttributeSupplier.Builder createAttributes() { @@ -162,7 +_,7 @@ - if ((this.temptGoal == null || this.temptGoal.isRunning()) && !this.isTrusting() && this.isFood(itemInHand) && player.distanceToSqr(this) < 9.0) { - this.usePlayerItem(player, hand, itemInHand); + if ((this.temptGoal == null || this.temptGoal.isRunning()) && !this.isTrusting() && this.isFood(itemStack) && player.distanceToSqr(this) < 9.0) { + this.usePlayerItem(player, hand, itemStack); if (!this.level().isClientSide()) { - if (this.random.nextInt(3) == 0) { + if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/Pufferfish.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/Pufferfish.java.patch index db4ed72b0b8f..eafe8584e9f1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/Pufferfish.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/Pufferfish.java.patch @@ -38,7 +38,7 @@ } } @@ -138,7 +_,7 @@ - private void touch(ServerLevel level, Mob mob) { + private void touch(final ServerLevel level, final Mob mob) { int puffState = this.getPuffState(); if (mob.hurtServer(level, this.damageSources().mobAttack(this), 1 + puffState)) { - mob.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * puffState, 0), this); @@ -50,8 +50,8 @@ serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.PUFFER_FISH_STING, 0.0F)); } -- entity.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * puffState, 0), this); -+ entity.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * puffState, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit +- player.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * puffState, 0), this); ++ player.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * puffState, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch index a55197acb9e7..e4f46df3d56f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/fish/WaterAnimal.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/entity/animal/fish/WaterAnimal.java +++ b/net/minecraft/world/entity/animal/fish/WaterAnimal.java -@@ -72,6 +_,10 @@ +@@ -76,6 +_,10 @@ ) { int seaLevel = level.getSeaLevel(); - int i = seaLevel - 13; + int minSpawnLevel = seaLevel - 13; + // Paper start - Make water animal spawn height configurable + seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel); -+ i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i); ++ minSpawnLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(minSpawnLevel); + // Paper end - Make water animal spawn height configurable - return pos.getY() >= i + return pos.getY() >= minSpawnLevel && pos.getY() <= seaLevel && level.getFluidState(pos.below()).is(FluidTags.WATER) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch index e9b25ee2248e..19a985077464 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/fox/Fox.java +++ b/net/minecraft/world/entity/animal/fox/Fox.java -@@ -440,7 +_,7 @@ +@@ -447,7 +_,7 @@ input.read("Trusted", TRUSTED_LIST_CODEC).orElse(List.of()).forEach(this::addTrustedEntity); this.setSleeping(input.getBooleanOr("Sleeping", false)); this.setVariant(input.read("Type", Fox.Variant.CODEC).orElse(Fox.Variant.DEFAULT)); @@ -9,58 +9,58 @@ this.setIsCrouching(input.getBooleanOr("Crouching", false)); if (this.level() instanceof ServerLevel) { this.setTargetGoals(); -@@ -457,6 +_,12 @@ +@@ -464,6 +_,12 @@ } - public void setSitting(boolean sitting) { + public void setSitting(final boolean value) { + // Paper start - Add EntityToggleSitEvent -+ this.setSitting(sitting, true); ++ this.setSitting(value, true); + } -+ public void setSitting(boolean sitting, boolean fireEvent) { -+ if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; ++ public void setSitting(final boolean value, final boolean fireEvent) { ++ if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), value).callEvent()) return; + // Paper end - Add EntityToggleSitEvent - this.setFlag(FLAG_SITTING, sitting); + this.setFlag(FLAG_SITTING, value); } -@@ -516,19 +_,20 @@ - itemEntity.setPickUpDelay(40); - itemEntity.setThrower(this); +@@ -523,19 +_,20 @@ + thrownItem.setPickUpDelay(40); + thrownItem.setThrower(this); this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F); -- this.level().addFreshEntity(itemEntity); -+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity); // Paper - Call EntityDropItemEvent +- this.level().addFreshEntity(thrownItem); ++ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), thrownItem); // Paper - Call EntityDropItemEvent } } - private void dropItemStack(ItemStack stack) { - ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack); + private void dropItemStack(final ItemStack itemStack) { + ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); - this.level().addFreshEntity(itemEntity); + this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity); // Paper - Call EntityDropItemEvent } @Override - protected void pickUpItem(ServerLevel level, ItemEntity entity) { - ItemStack item = entity.getItem(); -- if (this.canHoldItem(item)) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, item.getCount() - 1, !this.canHoldItem(item)).isCancelled()) { // CraftBukkit - call EntityPickupItemEvent -+ item = entity.getItem(); // CraftBukkit - update item after event - int count = item.getCount(); + protected void pickUpItem(final ServerLevel level, final ItemEntity entity) { + ItemStack itemStack = entity.getItem(); +- if (this.canHoldItem(itemStack)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, itemStack.getCount() - 1, !this.canHoldItem(itemStack)).isCancelled()) { // CraftBukkit - call EntityPickupItemEvent ++ itemStack = entity.getItem(); // CraftBukkit - update item after event + int count = itemStack.getCount(); if (count > 1) { - this.dropItemStack(item.split(count - 1)); -@@ -539,7 +_,7 @@ - this.setItemSlot(EquipmentSlot.MAINHAND, item.split(1)); + this.dropItemStack(itemStack.split(count - 1)); +@@ -546,7 +_,7 @@ + this.setItemSlot(EquipmentSlot.MAINHAND, itemStack.split(1)); this.setGuaranteedDrop(EquipmentSlot.MAINHAND); - this.take(entity, item.getCount()); + this.take(entity, itemStack.getCount()); - entity.discard(); + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause this.ticksSinceEaten = 0; } } -@@ -630,12 +_,12 @@ +@@ -637,12 +_,12 @@ } @Override -- public void setTarget(@Nullable LivingEntity target) { -+ public boolean setTarget(@Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit +- public void setTarget(final @Nullable LivingEntity target) { ++ public boolean setTarget(final @Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit if (this.isDefending() && target == null) { this.setDefending(false); } @@ -69,13 +69,13 @@ + return super.setTarget(target, reason); // CraftBukkit } - void wakeUp() { -@@ -696,15 +_,33 @@ - return this.getTrustedEntities().anyMatch(entityReference -> entityReference.matches(entity)); + private void wakeUp() { +@@ -703,15 +_,33 @@ + return this.getTrustedEntities().anyMatch(trusted -> trusted.matches(entity)); } - @Override -- protected void dropAllDeathLoot(ServerLevel level, DamageSource damageSource) { +- protected void dropAllDeathLoot(final ServerLevel level, final DamageSource source) { + // Paper start - handle the bitten item separately like vanilla + @Override + protected boolean shouldSkipLoot(EquipmentSlot slot) { @@ -85,16 +85,16 @@ + + @Override + // Paper start - Cancellable death event -+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel level, DamageSource damageSource) { - ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.MAINHAND); -- if (!itemBySlot.isEmpty()) { ++ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(final ServerLevel level, final DamageSource source) { + ItemStack itemStack = this.getItemBySlot(EquipmentSlot.MAINHAND); +- if (!itemStack.isEmpty()) { + boolean releaseMouth = false; -+ if (!itemBySlot.isEmpty() && level.getGameRules().get(GameRules.MOB_DROPS)) { // Fix MC-153010 - this.spawnAtLocation(level, itemBySlot); ++ if (!itemStack.isEmpty() && level.getGameRules().get(GameRules.MOB_DROPS)) { // Fix MC-153010 + this.spawnAtLocation(level, itemStack); + releaseMouth = true; + } + -+ org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(level, damageSource); ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(level, source); + // Below is code to drop + if (deathEvent == null || deathEvent.isCancelled()) return deathEvent; + @@ -103,20 +103,20 @@ this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); } -- super.dropAllDeathLoot(level, damageSource); +- super.dropAllDeathLoot(level, source); + return deathEvent; // Paper - Cancellable death event } - public static boolean isPathClear(Fox fox, LivingEntity livingEntity) { -@@ -877,6 +_,19 @@ - fox.addTrustedEntity(loveCause1); + public static boolean isPathClear(final Fox fox, final LivingEntity target) { +@@ -896,6 +_,19 @@ + offspring.addTrustedEntity(partnerLoveCause); } + // CraftBukkit start - call EntityBreedEvent -+ fox.setAge(-24000); -+ fox.snapTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); ++ offspring.setAge(-24000); ++ offspring.snapTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); + int experience = this.animal.getRandom().nextInt(7) + 1; -+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(fox, this.animal, this.partner, loveCause, this.animal.breedItem, experience); ++ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(offspring, this.animal, this.partner, loveCause, this.animal.breedItem, experience); + if (entityBreedEvent.isCancelled()) { + this.animal.resetLove(); + this.partner.resetLove(); @@ -125,32 +125,32 @@ + experience = entityBreedEvent.getExperience(); + // CraftBukkit end - call EntityBreedEvent + - if (serverPlayer != null) { - serverPlayer.awardStat(Stats.ANIMALS_BRED); - CriteriaTriggers.BRED_ANIMALS.trigger(serverPlayer, this.animal, this.partner, fox); -@@ -886,14 +_,12 @@ + if (loveCause != null) { + loveCause.awardStat(Stats.ANIMALS_BRED); + CriteriaTriggers.BRED_ANIMALS.trigger(loveCause, this.animal, this.partner, offspring); +@@ -905,14 +_,12 @@ this.partner.setAge(6000); this.animal.resetLove(); this.partner.resetLove(); -- fox.setAge(-24000); -- fox.snapTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); -- this.level.addFreshEntityWithPassengers(fox); -+ this.level.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason +- offspring.setAge(-24000); +- offspring.snapTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); +- this.level.addFreshEntityWithPassengers(offspring); ++ this.level.addFreshEntityWithPassengers(offspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason this.level.broadcastEntityEvent(this.animal, EntityEvent.IN_LOVE_HEARTS); - if (this.level.getGameRules().get(GameRules.MOB_DROPS)) { + if (experience > 0 && this.level.getGameRules().get(GameRules.MOB_DROPS)) { // Paper - call EntityBreedEvent this.level .addFreshEntity( - new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1) -+ new ExperienceOrb(this.level, this.animal.position(), net.minecraft.world.phys.Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, fox) // Paper - call EntityBreedEvent, add spawn context ++ new ExperienceOrb(this.level, this.animal.position(), net.minecraft.world.phys.Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, offspring) // Paper - call EntityBreedEvent, add spawn context ); } } -@@ -957,6 +_,7 @@ - private void pickSweetBerries(BlockState state) { - int ageValue = state.getValue(SweetBerryBushBlock.AGE); +@@ -977,6 +_,7 @@ + private void pickSweetBerries(final BlockState state) { + int age = state.getValue(SweetBerryBushBlock.AGE); state.setValue(SweetBerryBushBlock.AGE, 1); + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Fox.this, this.blockPos, state.setValue(SweetBerryBushBlock.AGE, 1))) return; // CraftBukkit - call EntityChangeBlockEvent - int i = 1 + Fox.this.level().random.nextInt(2) + (ageValue == 3 ? 1 : 0); - ItemStack itemBySlot = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND); - if (itemBySlot.isEmpty()) { + int count = 1 + Fox.this.level().getRandom().nextInt(2) + (age == 3 ? 1 : 0); + ItemStack heldItem = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND); + if (heldItem.isEmpty()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Frog.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Frog.java.patch index ae9192ae64c2..432dea63b573 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Frog.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Frog.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/animal/frog/Frog.java +++ b/net/minecraft/world/entity/animal/frog/Frog.java -@@ -285,7 +_,12 @@ +@@ -257,7 +_,12 @@ @Override - public void spawnChildFromBreeding(ServerLevel level, Animal partner) { + public void spawnChildFromBreeding(final ServerLevel level, final Animal partner) { - this.finalizeSpawnChildFromBreeding(level, partner, null); + // Paper start - Add EntityFertilizeEggEvent event + final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, partner); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/ShootTongue.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/ShootTongue.java.patch index 3b1480d7f079..6ea45dab5671 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/ShootTongue.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/ShootTongue.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/animal/frog/ShootTongue.java +++ b/net/minecraft/world/entity/animal/frog/ShootTongue.java @@ -94,7 +_,7 @@ - if (entity.isAlive()) { - frog.doHurtTarget(level, entity); - if (!entity.isAlive()) { -- entity.remove(Entity.RemovalReason.KILLED); -+ entity.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + if (target.isAlive()) { + body.doHurtTarget(level, target); + if (!target.isAlive()) { +- target.remove(Entity.RemovalReason.KILLED); ++ target.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Tadpole.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Tadpole.java.patch index 2d3ea622dc8d..b7a18eef6cea 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Tadpole.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/frog/Tadpole.java.patch @@ -1,75 +1,23 @@ --- a/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -64,6 +_,7 @@ - MemoryModuleType.BREED_TARGET, - MemoryModuleType.IS_PANICKING - ); -+ public boolean ageLocked; // Paper - - public Tadpole(EntityType type, Level level) { - super(type, level); -@@ -115,7 +_,7 @@ - @Override - public void aiStep() { - super.aiStep(); -- if (!this.level().isClientSide()) { -+ if (!this.level().isClientSide() && !this.ageLocked) { // Paper - this.setAge(this.age + 1); - } - } -@@ -124,12 +_,14 @@ - protected void addAdditionalSaveData(ValueOutput output) { - super.addAdditionalSaveData(output); - output.putInt("Age", this.age); -+ output.putBoolean("AgeLocked", this.ageLocked); // Paper - } - - @Override - protected void readAdditionalSaveData(ValueInput input) { - super.readAdditionalSaveData(input); - this.setAge(input.getIntOr("Age", 0)); -+ this.ageLocked = input.getBooleanOr("AgeLocked", false); // Paper - } - - @Override -@@ -170,13 +_,19 @@ - @Override - public void saveToBucketTag(ItemStack stack) { - Bucketable.saveDefaultDataToBucketTag(this, stack); -- CustomData.update(DataComponents.BUCKET_ENTITY_DATA, stack, compoundTag -> compoundTag.putInt("Age", this.getAge())); -+ // Paper start - Save tadpole age -+ CustomData.update(DataComponents.BUCKET_ENTITY_DATA, stack, compoundTag -> { -+ compoundTag.putInt("Age", this.getAge()); -+ compoundTag.putBoolean("AgeLocked", this.ageLocked); -+ }); -+ // Paper end - Save tadpole age - } - - @Override - public void loadFromBucketTag(CompoundTag tag) { - Bucketable.loadDefaultDataFromBucketTag(this, tag); - tag.getInt("Age").ifPresent(this::setAge); -+ this.ageLocked = tag.getBooleanOr("AgeLocked", false); // Paper - } - - @Override -@@ -208,6 +_,7 @@ +@@ -127,7 +_,7 @@ + entityData.define(AGE_LOCKED, false); } - private void ageUp(int offset) { -+ if (this.ageLocked) return; // Paper - this.setAge(this.age + offset * 20); +- protected void setAgeLocked(final boolean locked) { ++ public void setAgeLocked(final boolean locked) { // Paper - public + this.entityData.set(AGE_LOCKED, locked); } -@@ -220,12 +_,17 @@ +@@ -236,12 +_,17 @@ private void ageUp() { if (this.level() instanceof ServerLevel serverLevel) { -- this.convertTo(EntityType.FROG, ConversionParams.single(this, false, false), mob -> { -+ Frog converted = this.convertTo(EntityType.FROG, ConversionParams.single(this, false, false), mob -> { // CraftBukkit - mob.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CONVERSION, null); - mob.setPersistenceRequired(); - mob.fudgePositionAfterSizeChange(this.getDimensions(this.getPose())); +- this.convertTo(EntityType.FROG, ConversionParams.single(this, false, false), frog -> { ++ Frog converted = this.convertTo(EntityType.FROG, ConversionParams.single(this, false, false), frog -> { // CraftBukkit + frog.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(frog.blockPosition()), EntitySpawnReason.CONVERSION, null); + frog.setPersistenceRequired(); + frog.fudgePositionAfterSizeChange(this.getDimensions(this.getPose())); this.playSound(SoundEvents.TADPOLE_GROW_UP, 0.15F, 1.0F); - }); + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch index a05540f3cdf0..6d7aa8763011 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/animal/goat/Goat.java +++ b/net/minecraft/world/entity/animal/goat/Goat.java -@@ -234,13 +_,22 @@ - public InteractionResult mobInteract(Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.is(Items.BUCKET) && !this.isBaby()) { +@@ -213,13 +_,22 @@ + public InteractionResult mobInteract(final Player player, final InteractionHand hand) { + ItemStack heldItem = player.getItemInHand(hand); + if (heldItem.is(Items.BUCKET) && !this.isBaby()) { + // CraftBukkit start - Got milk? -+ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand); ++ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(player.level(), player, this.blockPosition(), this.blockPosition(), null, heldItem, Items.MILK_BUCKET, hand); + + if (event.isCancelled()) { + player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync @@ -13,29 +13,29 @@ + } + // CraftBukkit end player.playSound(this.getMilkingSound(), 1.0F, 1.0F); -- ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, Items.MILK_BUCKET.getDefaultInstance()); -+ ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit - player.setItemInHand(hand, itemStack); +- ItemStack bucketOrMilkBucket = ItemUtils.createFilledResult(heldItem, player, Items.MILK_BUCKET.getDefaultInstance()); ++ ItemStack bucketOrMilkBucket = ItemUtils.createFilledResult(heldItem, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + player.setItemInHand(hand, bucketOrMilkBucket); return InteractionResult.SUCCESS; } else { -+ boolean isFood = this.isFood(itemInHand); // Paper - track before stack is possibly decreased to 0 (Fixes MC-244739) ++ boolean isFood = this.isFood(heldItem); // Paper - track before stack is possibly decreased to 0 (Fixes MC-244739) InteractionResult interactionResult = super.mobInteract(player, hand); -- if (interactionResult.consumesAction() && this.isFood(itemInHand)) { +- if (interactionResult.consumesAction() && this.isFood(heldItem)) { + if (interactionResult.consumesAction() && isFood) { // Paper this.playEatingSound(); } -@@ -346,8 +_,7 @@ - double d1 = Mth.randomBetween(this.random, 0.3F, 0.7F); - double d2 = Mth.randomBetween(this.random, -0.2F, 0.2F); - ItemEntity itemEntity = new ItemEntity(this.level(), vec3.x(), vec3.y(), vec3.z(), itemStack, d, d1, d2); -- this.level().addFreshEntity(itemEntity); -- return true; -+ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity) != null; // Paper - Call EntityDropItemEvent +@@ -328,8 +_,7 @@ + double deltaY = Mth.randomBetween(this.random, 0.3F, 0.7F); + double deltaZ = Mth.randomBetween(this.random, -0.2F, 0.2F); + ItemEntity itemEntity = new ItemEntity(this.level(), bodyPosition.x(), bodyPosition.y(), bodyPosition.z(), item, deltaX, deltaY, deltaZ); +- this.level().addFreshEntity(itemEntity); +- return true; ++ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity) != null; // Paper - Call EntityDropItemEvent + } } } - -@@ -378,4 +_,15 @@ +@@ -352,4 +_,15 @@ ) { return level.getBlockState(pos.below()).is(BlockTags.GOATS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos); } @@ -43,10 +43,10 @@ + // Paper start - Goat ram API + public void ram(net.minecraft.world.entity.LivingEntity entity) { + Brain brain = this.getBrain(); -+ brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); -+ brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); -+ brain.eraseMemory(MemoryModuleType.BREED_TARGET); -+ brain.eraseMemory(MemoryModuleType.TEMPTING_PLAYER); ++ brain.setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.RAM_TARGET, entity.position()); ++ brain.eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.RAM_COOLDOWN_TICKS); ++ brain.eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.BREED_TARGET); ++ brain.eraseMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.TEMPTING_PLAYER); + brain.setActiveActivityIfPossible(net.minecraft.world.entity.schedule.Activity.RAM); + } + // Paper end - Goat ram API diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch index 3257d8bb7bbd..e5842b62dbdd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/golem/CopperGolem.java +++ b/net/minecraft/world/entity/animal/golem/CopperGolem.java -@@ -57,8 +_,8 @@ +@@ -58,8 +_,8 @@ import org.jspecify.annotations.Nullable; public class CopperGolem extends AbstractGolem implements ContainerUser, Shearable { @@ -11,7 +11,7 @@ private static final int WEATHERING_TICK_FROM = 504000; private static final int WEATHERING_TICK_TO = 552000; private static final int SPIN_ANIMATION_MIN_COOLDOWN = 200; -@@ -75,7 +_,7 @@ +@@ -79,7 +_,7 @@ ); private @Nullable BlockPos openedChestPos; private @Nullable UUID lastLightningBoltUUID; @@ -20,32 +20,32 @@ private int idleAnimationStartTick = 0; private final AnimationState idleAnimationState = new AnimationState(); private final AnimationState interactionGetItemAnimationState = new AnimationState(); -@@ -219,7 +_,15 @@ +@@ -218,7 +_,15 @@ Level level = this.level(); - if (itemInHand.is(Items.SHEARS) && this.readyForShearing()) { + if (itemStack.is(Items.SHEARS) && this.readyForShearing()) { if (level instanceof ServerLevel serverLevel) { -- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); +- this.shear(serverLevel, SoundSource.PLAYERS, itemStack); + // Paper start -+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); -+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(serverLevel, itemStack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemStack, hand, drops); + if (event != null) { + if (event.isCancelled()) return InteractionResult.PASS; + drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); + } -+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); ++ this.shear(serverLevel, SoundSource.PLAYERS, itemStack, drops); + // Paper end this.gameEvent(GameEvent.SHEAR, player); - itemInHand.hurtAndBreak(1, player, hand); + itemStack.hurtAndBreak(1, player, hand); } -@@ -282,20 +_,27 @@ +@@ -281,20 +_,27 @@ - private void turnToStatue(ServerLevel level) { - BlockPos blockPos = this.blockPosition(); + private void turnToStatue(final ServerLevel level) { + BlockPos pos = this.blockPosition(); - level.setBlock( -- blockPos, +- pos, + // Paper start - call EntityChangeBlockEvent + //level.setBlock( -+ // blockPos, ++ // pos, + BlockState newState = Blocks.OXIDIZED_COPPER_GOLEM_STATUE .defaultBlockState() @@ -58,12 +58,12 @@ + .setValue(CopperGolemStatueBlock.FACING, Direction.fromYRot(this.getYRot())); + // Block.UPDATE_ALL + //); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, newState)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, newState)) { + return; + } -+ level.setBlock(blockPos, newState, Block.UPDATE_ALL); ++ level.setBlock(pos, newState, Block.UPDATE_ALL); + // Paper end - call EntityChangeBlockEvent - if (level.getBlockEntity(blockPos) instanceof CopperGolemStatueBlockEntity copperGolemStatueBlockEntity) { + if (level.getBlockEntity(pos) instanceof CopperGolemStatueBlockEntity copperGolemStatueBlockEntity) { copperGolemStatueBlockEntity.createStatue(this); this.dropPreservedEquipment(level); - this.discard(); @@ -71,17 +71,17 @@ this.playSound(SoundEvents.COPPER_GOLEM_BECOME_STATUE); if (this.isLeashed()) { if (level.getGameRules().get(GameRules.ENTITY_DROPS)) { -@@ -425,12 +_,32 @@ +@@ -424,12 +_,32 @@ } @Override -- public void shear(ServerLevel level, SoundSource source, ItemStack shears) { +- public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { + // Paper start -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { - level.playSound(null, this, SoundEvents.COPPER_GOLEM_SHEAR, source, 1.0F, 1.0F); -- ItemStack itemBySlot = this.getItemBySlot(EQUIPMENT_SLOT_ANTENNA); ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool, final java.util.List drops) { + level.playSound(null, this, SoundEvents.COPPER_GOLEM_SHEAR, soundSource, 1.0F, 1.0F); +- ItemStack itemStack = this.getItemBySlot(EQUIPMENT_SLOT_ANTENNA); this.setItemSlot(EQUIPMENT_SLOT_ANTENNA, ItemStack.EMPTY); -- this.spawnAtLocation(level, itemBySlot, 1.5F); +- this.spawnAtLocation(level, itemStack, 1.5F); - } + for (ItemStack drop : drops) { + this.forceDrops = true; @@ -91,12 +91,12 @@ + } + + @Override -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears) { -+ this.shear(level, source, shears, this.generateDefaultDrops(level, shears)); ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { ++ this.shear(level, soundSource, tool, this.generateDefaultDrops(level, tool)); + } + + @Override -+ public java.util.List generateDefaultDrops(final net.minecraft.server.level.ServerLevel serverLevel, final net.minecraft.world.item.ItemStack shears) { ++ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + if (!this.readyForShearing()) { + return java.util.Collections.emptyList(); + } @@ -108,15 +108,15 @@ @Override public boolean readyForShearing() { -@@ -444,9 +_,13 @@ +@@ -443,9 +_,13 @@ } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { -- super.actuallyHurt(level, damageSource, amount); +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg) { +- super.actuallyHurt(level, source, dmg); + // CraftBukkit start - void -> boolean -+ protected boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { -+ boolean damageResult = super.actuallyHurt(level, damageSource, amount, event); ++ protected boolean actuallyHurt(final ServerLevel level, final DamageSource source, final float dmg, final org.bukkit.event.entity.EntityDamageEvent event) { ++ boolean damageResult = super.actuallyHurt(level, source, dmg, event); + if (!damageResult) return false; + // CraftBukkit end this.setState(CopperGolemState.IDLE); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch index 9f6fe1934d89..afbb13319fe3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/entity/animal/golem/IronGolem.java @@ -106,7 +_,7 @@ @Override - protected void doPush(Entity entity) { + protected void doPush(final Entity entity) { if (entity instanceof Enemy && !(entity instanceof Creeper) && this.getRandom().nextInt(20) == 0) { - this.setTarget((LivingEntity)entity); + this.setTarget((LivingEntity)entity, org.bukkit.event.entity.EntityTargetLivingEntityEvent.TargetReason.COLLISION); // CraftBukkit - set reason @@ -10,11 +10,11 @@ super.doPush(entity); @@ -304,7 +_,7 @@ - BlockPos blockPos = this.blockPosition(); - BlockPos blockPos1 = blockPos.below(); - BlockState blockState = level.getBlockState(blockPos1); -- if (!blockState.entityCanStandOn(level, blockPos1, this)) { -+ if (!blockState.entityCanStandOn(level, blockPos1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air + BlockPos pos = this.blockPosition(); + BlockPos belowPos = pos.below(); + BlockState below = level.getBlockState(belowPos); +- if (!below.entityCanStandOn(level, belowPos, this)) { ++ if (!below.entityCanStandOn(level, belowPos, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air return false; } else { for (int i = 1; i < 3; i++) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch index 730fcd93d943..00b0d31e243c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/SnowGolem.java.patch @@ -10,23 +10,23 @@ if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) { @@ -107,7 +_,7 @@ - int floor2 = Mth.floor(this.getZ() + (i / 2 % 2 * 2 - 1) * 0.25F); - BlockPos blockPos = new BlockPos(floor, floor1, floor2); - if (this.level().getBlockState(blockPos).isAir() && blockState.canSurvive(this.level(), blockPos)) { -- this.level().setBlockAndUpdate(blockPos, blockState); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this.level(), blockPos, blockState, net.minecraft.world.level.block.Block.UPDATE_ALL, this)) continue; // CraftBukkit - this.level().gameEvent(GameEvent.BLOCK_PLACE, blockPos, GameEvent.Context.of(this, blockState)); + int zz = Mth.floor(this.getZ() + (i / 2 % 2 * 2 - 1) * 0.25F); + BlockPos snowPos = new BlockPos(xx, yy, zz); + if (this.level().getBlockState(snowPos).isAir() && snow.canSurvive(this.level(), snowPos)) { +- this.level().setBlockAndUpdate(snowPos, snow); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this.level(), snowPos, snow, net.minecraft.world.level.block.Block.UPDATE_ALL, this)) continue; // CraftBukkit + this.level().gameEvent(GameEvent.BLOCK_PLACE, snowPos, GameEvent.Context.of(this, snow)); } } -@@ -135,7 +_,19 @@ - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.is(Items.SHEARS) && this.readyForShearing()) { - if (this.level() instanceof ServerLevel serverLevel) { -- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); +@@ -138,7 +_,19 @@ + ItemStack itemStack = player.getItemInHand(hand); + if (itemStack.is(Items.SHEARS) && this.readyForShearing()) { + if (this.level() instanceof ServerLevel level) { +- this.shear(level, SoundSource.PLAYERS, itemStack); + // CraftBukkit start + // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); -+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(level, itemStack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemStack, hand, drops); + if (event != null) { + if (event.isCancelled()) { + return InteractionResult.PASS; @@ -35,40 +35,40 @@ + // Paper end - custom shear drops + } + // CraftBukkit end -+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); // Paper - custom shear drops ++ this.shear(level, SoundSource.PLAYERS, itemStack, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); - itemInHand.hurtAndBreak(1, player, hand.asEquipmentSlot()); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); } -@@ -148,11 +_,29 @@ +@@ -151,9 +_,31 @@ @Override - public void shear(ServerLevel level, SoundSource source, ItemStack shears) { + public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { + // Paper start - custom shear drops -+ this.shear(level, source, shears, this.generateDefaultDrops(level, shears)); ++ this.shear(level, soundSource, tool, this.generateDefaultDrops(level, tool)); + } + + @Override -+ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack shears) { ++ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (ignored, stack) -> { ++ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SNOW_GOLEM, tool, (ignored, stack) -> { + drops.add(stack); + }); + return drops; + } + + @Override -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool, final java.util.List drops) { + // Paper end - custom shear drops - level.playSound(null, this, SoundEvents.SNOW_GOLEM_SHEAR, source, 1.0F, 1.0F); + level.playSound(null, this, SoundEvents.SNOW_GOLEM_SHEAR, soundSource, 1.0F, 1.0F); this.setPumpkin(false); -- this.dropFromShearingLootTable( -- level, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (serverLevel, itemStack) -> this.spawnAtLocation(serverLevel, itemStack, this.getEyeHeight()) -- ); -+ drops.forEach(itemStack -> { // Paper - custom shear drops +- this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SNOW_GOLEM, tool, (l, drop) -> this.spawnAtLocation(l, drop, this.getEyeHeight())); ++ // Paper start - custom shear drops ++ drops.forEach(drop -> { + this.forceDrops = true; // CraftBukkit -+ this.spawnAtLocation(level, itemStack, this.getEyeHeight()); ++ this.spawnAtLocation(level, drop, this.getEyeHeight()); + this.forceDrops = false; // CraftBukkit + }); ++ // Paper end - custom shear drops } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch index 860f951bc384..f1e78e4bb704 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java +++ b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java -@@ -306,8 +_,12 @@ +@@ -314,8 +_,12 @@ } @Override -- protected void removePassenger(Entity passenger) { +- protected void removePassenger(final Entity passenger) { - super.removePassenger(passenger); + // Paper start - cancellable passengers -+ protected boolean removePassenger(Entity passenger, boolean suppressCancellation) { ++ protected boolean removePassenger(final Entity passenger, final boolean suppressCancellation) { + if (!super.removePassenger(passenger, suppressCancellation)) { + return false; + } @@ -15,7 +15,7 @@ if (!this.level().isClientSide()) { this.setServerStillTimeout(10); } -@@ -316,6 +_,7 @@ +@@ -324,6 +_,7 @@ this.clearHome(); this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.HARNESS_GOGGLES_UP, this.getSoundSource(), 1.0F, 1.0F); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch index 8d376e3a0e5a..3d324243e54b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java +++ b/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java -@@ -139,8 +_,12 @@ +@@ -141,8 +_,12 @@ ) { int seaLevel = level.getSeaLevel(); - int i = seaLevel - 25; + int minSpawnLevel = seaLevel - 25; + // Paper start - Make water animal spawn height configurable + seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel - 5); -+ i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i); ++ minSpawnLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(minSpawnLevel); + // Paper end - Make water animal spawn height configurable - return pos.getY() >= i + return pos.getY() >= minSpawnLevel - && pos.getY() <= seaLevel - 5 + && pos.getY() <= seaLevel // Paper - Make water animal spawn height configurable && level.getFluidState(pos.below()).is(FluidTags.WATER) @@ -16,37 +16,28 @@ } @@ -263,7 +_,7 @@ boolean hasEffect = player.hasEffect(MobEffects.BREATH_OF_THE_NAUTILUS); - boolean flag = level.getGameTime() % 40L == 0L; - if (!hasEffect || flag) { + boolean shouldRefresh = level.getGameTime() % 40L == 0L; + if (!hasEffect || shouldRefresh) { - player.addEffect(new MobEffectInstance(MobEffects.BREATH_OF_THE_NAUTILUS, 60, 0, true, true, true)); + player.addEffect(new MobEffectInstance(MobEffects.BREATH_OF_THE_NAUTILUS, 60, 0, true, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.NAUTILUS); // Paper - Add cause } } } -@@ -405,7 +_,7 @@ - - if (this.isFood(itemInHand) && this.getHealth() < this.getMaxHealth()) { - FoodProperties foodProperties = itemInHand.get(DataComponents.FOOD); -- this.heal(foodProperties != null ? 2 * foodProperties.nutrition() : 1.0F); -+ this.heal(foodProperties != null ? 2 * foodProperties.nutrition() : 1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add regain reason - this.usePlayerItem(player, hand, itemInHand); - this.playEatingSound(); - return InteractionResult.SUCCESS; -@@ -427,7 +_,7 @@ +@@ -431,7 +_,7 @@ } - private void tryToTame(Player player) { + private void tryToTame(final Player player) { - if (this.random.nextInt(3) == 0) { + if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call this.tame(player); this.navigation.stop(); this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED); -@@ -482,7 +_,7 @@ +@@ -486,7 +_,7 @@ protected void createInventory() { - SimpleContainer simpleContainer = this.inventory; + SimpleContainer old = this.inventory; - this.inventory = new SimpleContainer(this.getInventorySize()); + this.inventory = new SimpleContainer(this.getInventorySize(), (org.bukkit.entity.AbstractNautilus) this.getBukkitEntity()); // Paper - add owner - if (simpleContainer != null) { - int min = Math.min(simpleContainer.getContainerSize(), this.inventory.getContainerSize()); + if (old != null) { + int max = Math.min(old.getContainerSize(), this.inventory.getContainerSize()); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/Nautilus.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/Nautilus.java.patch index cc0fc86f7522..a17b2fd11b2b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/Nautilus.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/Nautilus.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/nautilus/Nautilus.java +++ b/net/minecraft/world/entity/animal/nautilus/Nautilus.java -@@ -109,8 +_,14 @@ +@@ -111,8 +_,14 @@ @Override public int getMaxAirSupply() { @@ -15,9 +15,9 @@ + } + // CraftBukkit end - protected void handleAirSupply(ServerLevel level, int airSupply) { + protected void handleAirSupply(final ServerLevel level, final int preTickAirSupply) { if (this.isAlive() && !this.isInWater()) { -@@ -120,7 +_,7 @@ +@@ -122,7 +_,7 @@ this.hurtServer(level, this.damageSources().dryOut(), 2.0F); } } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch index 8df23114de3b..422c65d8fdf1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/panda/Panda.java +++ b/net/minecraft/world/entity/animal/panda/Panda.java -@@ -130,6 +_,7 @@ +@@ -133,6 +_,7 @@ } - public void sit(boolean sitting) { -+ if (!new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; // Paper - Add EntityToggleSitEvent - this.setFlag(FLAG_SIT, sitting); + public void sit(final boolean value) { ++ if (!new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), value).callEvent()) return; // Paper - Add EntityToggleSitEvent + this.setFlag(FLAG_SIT, value); } -@@ -518,24 +_,28 @@ +@@ -517,24 +_,28 @@ for (Panda panda : level.getEntitiesOfClass(Panda.class, this.getBoundingBox().inflate(10.0))) { if (!panda.isBaby() && panda.onGround() && !panda.isInWater() && panda.canPerformAction()) { @@ -26,56 +26,56 @@ } @Override - protected void pickUpItem(ServerLevel level, ItemEntity entity) { + protected void pickUpItem(final ServerLevel level, final ItemEntity entity) { - if (this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && canPickUpAndEat(entity)) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, !(this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && Panda.canPickUpAndEat(entity))).isCancelled()) { // CraftBukkit this.onItemPickup(entity); - ItemStack item = entity.getItem(); - this.setItemSlot(EquipmentSlot.MAINHAND, item); + ItemStack itemStack = entity.getItem(); + this.setItemSlot(EquipmentSlot.MAINHAND, itemStack); this.setGuaranteedDrop(EquipmentSlot.MAINHAND); - this.take(entity, item.getCount()); + this.take(entity, itemStack.getCount()); - entity.discard(); + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } } -@@ -625,8 +_,9 @@ - this.usePlayerItem(player, hand, itemInHand); - this.ageUp((int)(-this.getAge() / 20 * 0.1F), true); - } else if (!this.level().isClientSide() && this.getAge() == 0 && this.canFallInLove()) { -+ final ItemStack breedCopy = itemInHand.copy(); // Paper - Fix EntityBreedEvent copying - this.usePlayerItem(player, hand, itemInHand); -- this.setInLove(player); -+ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying - } else { - if (!(this.level() instanceof ServerLevel serverLevel) || this.isSitting() || this.isInWater()) { - return InteractionResult.PASS; -@@ -636,7 +_,9 @@ - this.eat(true); - ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.MAINHAND); - if (!itemBySlot.isEmpty() && !player.hasInfiniteMaterials()) { -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.spawnAtLocation(serverLevel, itemBySlot); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles +@@ -629,8 +_,9 @@ } - this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(itemInHand.getItem(), 1)); -@@ -855,7 +_,7 @@ + if (!this.level().isClientSide() && this.getAge() == 0 && this.canFallInLove()) { ++ final ItemStack breedCopy = interactionItemStack.copy(); // Paper - Fix EntityBreedEvent copying + this.usePlayerItem(player, hand, interactionItemStack); +- this.setInLove(player); ++ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying + } else { + if (!(this.level() instanceof ServerLevel level) || this.isSitting() || this.isInWater()) { + return InteractionResult.PASS; +@@ -640,7 +_,9 @@ + this.eat(true); + ItemStack pandasCurrentItem = this.getItemBySlot(EquipmentSlot.MAINHAND); + if (!pandasCurrentItem.isEmpty() && !player.hasInfiniteMaterials()) { ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.spawnAtLocation(level, pandasCurrentItem); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(interactionItemStack.getItem(), 1)); +@@ -862,7 +_,7 @@ @Override - protected void alertOther(Mob mob, LivingEntity target) { - if (mob instanceof Panda && mob.isAggressive()) { -- mob.setTarget(target); -+ mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); // CraftBukkit + protected void alertOther(final Mob other, final LivingEntity hurtByMob) { + if (other instanceof Panda && other.isAggressive()) { +- other.setTarget(hurtByMob); ++ other.setTarget(hurtByMob, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); // CraftBukkit } } } -@@ -1084,7 +_,9 @@ +@@ -1093,7 +_,9 @@ public void stop() { - ItemStack itemBySlot = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND); - if (!itemBySlot.isEmpty()) { + ItemStack itemStack = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND); + if (!itemStack.isEmpty()) { + Panda.this.forceDrops = true; // Paper - Add missing forceDrop toggles - Panda.this.spawnAtLocation(getServerLevel(Panda.this.level()), itemBySlot); + Panda.this.spawnAtLocation(getServerLevel(Panda.this.level()), itemStack); + Panda.this.forceDrops = false; // Paper - Add missing forceDrop toggles Panda.this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); - int i = Panda.this.isLazy() ? Panda.this.random.nextInt(50) + 10 : Panda.this.random.nextInt(150) + 10; - this.cooldown = Panda.this.tickCount + i * 20; + int waitSeconds = Panda.this.isLazy() ? Panda.this.random.nextInt(50) + 10 : Panda.this.random.nextInt(150) + 10; + this.cooldown = Panda.this.tickCount + waitSeconds * 20; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch index 7db0b4f6b0e1..d5100bd9db08 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/parrot/Parrot.java +++ b/net/minecraft/world/entity/animal/parrot/Parrot.java -@@ -269,7 +_,7 @@ +@@ -270,7 +_,7 @@ } if (!this.level().isClientSide()) { @@ -9,16 +9,16 @@ this.tame(player); this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED); } else { -@@ -290,7 +_,7 @@ +@@ -291,7 +_,7 @@ } } else { - this.usePlayerItem(player, hand, itemInHand); + this.usePlayerItem(player, hand, itemStack); - this.addEffect(new MobEffectInstance(MobEffects.POISON, 900)); + this.addEffect(new MobEffectInstance(MobEffects.POISON, 900), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // CraftBukkit if (player.isCreative() || !this.isInvulnerable()) { this.hurt(this.damageSources().playerAttack(player), Float.MAX_VALUE); } -@@ -383,8 +_,8 @@ +@@ -384,8 +_,8 @@ } @Override @@ -29,16 +29,16 @@ } @Override -@@ -399,8 +_,13 @@ - if (this.isInvulnerableTo(level, damageSource)) { +@@ -400,8 +_,13 @@ + if (this.isInvulnerableTo(level, source)) { return false; } else { + // CraftBukkit start -+ if (!super.hurtServer(level, damageSource, amount)) { ++ if (!super.hurtServer(level, source, damage)) { + return false; + } this.setOrderedToSit(false); -- return super.hurtServer(level, damageSource, amount); +- return super.hurtServer(level, source, damage); + return true; + // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java.patch index 74075655549d..beb7868e9c5d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java +++ b/net/minecraft/world/entity/animal/parrot/ShoulderRidingEntity.java @@ -24,7 +_,7 @@ - this.saveWithoutId(tagValueOutput); - tagValueOutput.putString("id", this.getEncodeId()); - if (player.setEntityOnShoulder(tagValueOutput.buildResult())) { + this.saveWithoutId(output); + output.putString("id", this.getEncodeId()); + if (player.setEntityOnShoulder(output.buildResult())) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch index 7f3ffd06c1f0..1876e579f8ef 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/entity/animal/pig/Pig.java +++ b/net/minecraft/world/entity/animal/pig/Pig.java -@@ -178,7 +_,14 @@ - ZombifiedPiglin zombifiedPiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, false, true), mob -> { - mob.populateDefaultEquipmentSlots(this.getRandom(), level.getCurrentDifficultyAt(this.blockPosition())); - mob.setPersistenceRequired(); +@@ -198,7 +_,14 @@ + ZombifiedPiglin zombifiedPiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, false, true), zp -> { + zp.populateDefaultEquipmentSlots(this.getRandom(), level.getCurrentDifficultyAt(this.blockPosition())); + zp.setPersistenceRequired(); - }); + // CraftBukkit start + }, null, null); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPigZapEvent(this, lightning, zombifiedPiglin).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPigZapEvent(this, lightningBolt, zombifiedPiglin).isCancelled()) { + return; + } + level.addFreshEntity(zombifiedPiglin, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause + // CraftBukkit end if (zombifiedPiglin == null) { - super.thunderHit(level, lightning); + super.thunderHit(level, lightningBolt); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch index 6c26de099a9b..0deae6397e12 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/rabbit/Rabbit.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/rabbit/Rabbit.java +++ b/net/minecraft/world/entity/animal/rabbit/Rabbit.java -@@ -99,7 +_,7 @@ +@@ -113,7 +_,7 @@ super(type, level); this.jumpControl = new Rabbit.RabbitJumpControl(this); this.moveControl = new Rabbit.RabbitMoveControl(this); @@ -9,15 +9,15 @@ } @Override -@@ -589,9 +_,11 @@ +@@ -637,9 +_,11 @@ if (this.canRaid && block instanceof CarrotBlock) { - int ageValue = blockState.getValue(CarrotBlock.AGE); - if (ageValue == 0) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockPos, blockState.getFluidState().createLegacyBlock())) return; // CraftBukkit // Paper - fix wrong block state - level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS); - level.destroyBlock(blockPos, true, this.rabbit); + int carrotAge = blockState.getValue(CarrotBlock.AGE); + if (carrotAge == 0) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, cropsPos, blockState.getFluidState().createLegacyBlock())) return; // CraftBukkit // Paper - fix wrong block state + level.setBlock(cropsPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS); + level.destroyBlock(cropsPos, true, this.rabbit); } else { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockPos, blockState.setValue(CarrotBlock.AGE, ageValue - 1))) return; // CraftBukkit // Paper - fix wrong block state - level.setBlock(blockPos, blockState.setValue(CarrotBlock.AGE, ageValue - 1), Block.UPDATE_CLIENTS); - level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(this.rabbit)); - level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos, Block.getId(blockState)); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, cropsPos, blockState.setValue(CarrotBlock.AGE, carrotAge - 1))) return; // CraftBukkit // Paper - fix wrong block state + level.setBlock(cropsPos, blockState.setValue(CarrotBlock.AGE, carrotAge - 1), Block.UPDATE_CLIENTS); + level.gameEvent(GameEvent.BLOCK_CHANGE, cropsPos, GameEvent.Context.of(this.rabbit)); + level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, cropsPos, Block.getId(blockState)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/sheep/Sheep.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/sheep/Sheep.java.patch index bb206b657c75..c9a21385ac4b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/sheep/Sheep.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/sheep/Sheep.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/sheep/Sheep.java +++ b/net/minecraft/world/entity/animal/sheep/Sheep.java @@ -140,7 +_,19 @@ - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.is(Items.SHEARS)) { - if (this.level() instanceof ServerLevel serverLevel && this.readyForShearing()) { -- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); + ItemStack itemStack = player.getItemInHand(hand); + if (itemStack.is(Items.SHEARS)) { + if (this.level() instanceof ServerLevel level && this.readyForShearing()) { +- this.shear(level, SoundSource.PLAYERS, itemStack); + // CraftBukkit start + // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); -+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(level, itemStack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemStack, hand, drops); + if (event != null) { + if (event.isCancelled()) { + return InteractionResult.PASS; @@ -17,46 +17,46 @@ + // Paper end - custom shear drops + } + // CraftBukkit end -+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); // Paper - custom shear drops ++ this.shear(level, SoundSource.PLAYERS, itemStack, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); - itemInHand.hurtAndBreak(1, player, hand.asEquipmentSlot()); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); return InteractionResult.SUCCESS_SERVER; @@ -154,14 +_,28 @@ @Override - public void shear(ServerLevel level, SoundSource source, ItemStack shears) { + public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { + // Paper start - custom shear drops -+ this.shear(level, source, shears, this.generateDefaultDrops(level, shears)); ++ this.shear(level, soundSource, tool, this.generateDefaultDrops(level, tool)); + } + + @Override -+ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack shears) { ++ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SHEEP, shears, (ignored, stack) -> { -+ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); ++ this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SHEEP, tool, (ignored, stack) -> { ++ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1)); + }); + return drops; + } + + @Override -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool, final java.util.List drops) { + // Paper end - custom shear drops - level.playSound(null, this, SoundEvents.SHEEP_SHEAR, source, 1.0F, 1.0F); + level.playSound(null, this, SoundEvents.SHEEP_SHEAR, soundSource, 1.0F, 1.0F); - this.dropFromShearingLootTable( - level, - BuiltInLootTables.SHEAR_SHEEP, -- shears, -- (serverLevel, itemStack) -> { -- for (int i = 0; i < itemStack.getCount(); i++) { -- ItemEntity itemEntity = this.spawnAtLocation(serverLevel, itemStack.copyWithCount(1), 1.0F); +- tool, +- (l, drop) -> { +- for (int i = 0; i < drop.getCount(); i++) { +- ItemEntity entity = this.spawnAtLocation(l, drop.copyWithCount(1), 1.0F); + drops.forEach(itemStack -> { // Paper - custom drops - loop in generated default drops + { // Paper - custom drops - loop in generated default drops + this.forceDrops = true; // CraftBukkit -+ ItemEntity itemEntity = this.spawnAtLocation(level, itemStack, 1.0F); // Paper - custom drops - copy already done above ++ ItemEntity entity = this.spawnAtLocation(level, itemStack, 1.0F); // Paper - custom drops - copy already done above + this.forceDrops = false; // CraftBukkit - if (itemEntity != null) { - itemEntity.setDeltaMovement( - itemEntity.getDeltaMovement() + if (entity != null) { + entity.setDeltaMovement( + entity.getDeltaMovement() @@ -279,6 +_,7 @@ @Override @@ -64,4 +64,4 @@ + if (!new org.bukkit.event.entity.SheepRegrowWoolEvent((org.bukkit.entity.Sheep) this.getBukkitEntity()).callEvent()) return; // CraftBukkit super.ate(); this.setSheared(false); - if (this.isBaby()) { + if (this.canAgeUp()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch index 915d16ecb441..15676ec795c0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch @@ -1,35 +1,35 @@ --- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java +++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java -@@ -278,6 +_,13 @@ - this.dropFromGiftLootTable(serverLevel, BuiltInLootTables.SNIFFER_DIGGING, (serverLevel1, itemStack) -> { - ItemEntity itemEntity = new ItemEntity(this.level(), headBlock.getX(), headBlock.getY(), headBlock.getZ(), itemStack); - itemEntity.setDefaultPickUpDelay(); +@@ -288,6 +_,13 @@ + this.dropFromGiftLootTable(level, BuiltInLootTables.SNIFFER_DIGGING, (l, itemStack) -> { + ItemEntity entity = new ItemEntity(this.level(), head.getX(), head.getY(), head.getZ(), itemStack); + entity.setDefaultPickUpDelay(); + // CraftBukkit start - handle EntityDropItemEvent -+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entity.getBukkitEntity()); + org.bukkit.Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + // CraftBukkit end - serverLevel1.addFreshEntity(itemEntity); + l.addFreshEntity(entity); }); this.playSound(SoundEvents.SNIFFER_DROP_SEED, 1.0F, 1.0F); -@@ -336,12 +_,17 @@ +@@ -346,12 +_,17 @@ @Override - public void spawnChildFromBreeding(ServerLevel level, Animal partner) { + public void spawnChildFromBreeding(final ServerLevel level, final Animal partner) { + // Paper start - Add EntityFertilizeEggEvent event + final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, partner); + if (result.isCancelled()) return; + // Paper end - Add EntityFertilizeEggEvent event ItemStack itemStack = new ItemStack(Items.SNIFFER_EGG); - ItemEntity itemEntity = new ItemEntity(level, this.position().x(), this.position().y(), this.position().z(), itemStack); - itemEntity.setDefaultPickUpDelay(); + ItemEntity entity = new ItemEntity(level, this.position().x(), this.position().y(), this.position().z(), itemStack); + entity.setDefaultPickUpDelay(); - this.finalizeSpawnChildFromBreeding(level, partner, null); + this.finalizeSpawnChildFromBreeding(level, partner, null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event -+ if (this.spawnAtLocation(level, itemEntity) != null) { // Paper - Call EntityDropItemEvent ++ if (this.spawnAtLocation(level, entity) != null) { // Paper - Call EntityDropItemEvent this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F); -- level.addFreshEntity(itemEntity); +- level.addFreshEntity(entity); + } // Paper - Call EntityDropItemEvent } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch index b6389c8fc3e5..6cb1af19242e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/squid/Squid.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/entity/animal/squid/Squid.java +++ b/net/minecraft/world/entity/animal/squid/Squid.java -@@ -48,7 +_,7 @@ +@@ -51,7 +_,7 @@ - public Squid(EntityType type, Level level) { + public Squid(final EntityType type, final Level level) { super(type, level); - this.random.setSeed(this.getId()); + // this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/turtle/Turtle.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/turtle/Turtle.java.patch index f65385287f30..607e65c3a8fa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/turtle/Turtle.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/turtle/Turtle.java.patch @@ -3,9 +3,9 @@ @@ -256,7 +_,9 @@ protected void ageBoundaryReached() { super.ageBoundaryReached(); - if (!this.isBaby() && this.level() instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.MOB_DROPS)) { + if (!this.isBaby() && this.level() instanceof ServerLevel level && level.getGameRules().get(GameRules.MOB_DROPS)) { + this.forceDrops = true; // CraftBukkit - this.dropFromGiftLootTable(serverLevel, BuiltInLootTables.TURTLE_GROW, this::spawnAtLocation); + this.dropFromGiftLootTable(level, BuiltInLootTables.TURTLE_GROW, this::spawnAtLocation); + this.forceDrops = false; // CraftBukkit } } @@ -13,9 +13,9 @@ @@ -277,7 +_,7 @@ @Override - public void thunderHit(ServerLevel level, LightningBolt lightning) { + public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { - this.hurtServer(level, this.damageSources().lightningBolt(), Float.MAX_VALUE); -+ this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API ++ this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightningBolt), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API } @Override @@ -49,7 +49,7 @@ @Override @@ -448,14 +_,20 @@ - BlockPos blockPos = this.turtle.blockPosition(); + BlockPos turtlePos = this.turtle.blockPosition(); if (!this.turtle.isInWater() && this.isReachedTarget()) { if (this.turtle.layEggCounter < 1) { - this.turtle.setLayingEgg(true); @@ -61,12 +61,12 @@ + if (layEggEvent.callEvent() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()))) { + // Paper end - Turtle API Level level = this.turtle.level(); - level.playSound(null, blockPos, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + level.random.nextFloat() * 0.2F); - BlockPos blockPos1 = this.blockPos.above(); -- BlockState blockState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1); -+ BlockState blockState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper - level.setBlock(blockPos1, blockState, Block.UPDATE_ALL); - level.gameEvent(GameEvent.BLOCK_PLACE, blockPos1, GameEvent.Context.of(this.turtle, blockState)); + level.playSound(null, turtlePos, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + level.getRandom().nextFloat() * 0.2F); + BlockPos eggPos = this.blockPos.above(); +- BlockState eggState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1); ++ BlockState eggState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper + level.setBlock(eggPos, eggState, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_PLACE, eggPos, GameEvent.Context.of(this.turtle, eggState)); + } // CraftBukkit this.turtle.setHasEgg(false); this.turtle.setLayingEgg(false); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch index 73a3cd945133..601db61365af 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch @@ -1,36 +1,36 @@ --- a/net/minecraft/world/entity/animal/wolf/Wolf.java +++ b/net/minecraft/world/entity/animal/wolf/Wolf.java -@@ -397,16 +_,18 @@ - if (this.isInvulnerableTo(level, damageSource)) { +@@ -396,16 +_,18 @@ + if (this.isInvulnerableTo(level, source)) { return false; } else { -+ if (!super.hurtServer(level, damageSource, amount)) return false; // CraftBukkit ++ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit this.setOrderedToSit(false); -- return super.hurtServer(level, damageSource, amount); +- return super.hurtServer(level, source, damage); + return true; // CraftBukkit } } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { -+ public boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { // CraftBukkit - void -> boolean - if (!this.canArmorAbsorb(damageSource)) { -- super.actuallyHurt(level, damageSource, amount); -+ return super.actuallyHurt(level, damageSource, amount, event); // CraftBukkit +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, final float damage) { ++ public boolean actuallyHurt(final ServerLevel level, final DamageSource source, final float damage, final org.bukkit.event.entity.EntityDamageEvent event) { // CraftBukkit - void -> boolean + if (!this.canArmorAbsorb(source)) { +- super.actuallyHurt(level, source, damage); ++ return super.actuallyHurt(level, source, damage, event); // CraftBukkit } else { + if (event.isCancelled()) return false; // CraftBukkit - SPIGOT-7815: if the damage was cancelled, no need to run the wolf armor behaviour - ItemStack bodyArmorItem = this.getBodyArmorItem(); - int damageValue = bodyArmorItem.getDamageValue(); - int maxDamage = bodyArmorItem.getMaxDamage(); -@@ -426,6 +_,7 @@ + ItemStack armorBefore = this.getBodyArmorItem(); + int damageBefore = armorBefore.getDamageValue(); + int maxDamage = armorBefore.getMaxDamage(); +@@ -417,6 +_,7 @@ ); } } + return true; // CraftBukkit // Paper - return false ONLY if event was cancelled } - private boolean canArmorAbsorb(DamageSource damageSource) { -@@ -436,7 +_,7 @@ + private boolean canArmorAbsorb(final DamageSource source) { +@@ -427,7 +_,7 @@ protected void applyTamingSideEffects() { if (this.isTame()) { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(40.0); @@ -39,16 +39,7 @@ } else { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(8.0); } -@@ -461,7 +_,7 @@ - this.usePlayerItem(player, hand, itemInHand); - FoodProperties foodProperties = itemInHand.get(DataComponents.FOOD); - float f = foodProperties != null ? foodProperties.nutrition() : 1.0F; -- this.heal(2.0F * f); -+ this.heal(2.0F * f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit - return InteractionResult.SUCCESS; - } - -@@ -490,7 +_,7 @@ +@@ -477,7 +_,7 @@ this.setOrderedToSit(!this.isOrderedToSit()); this.jumping = false; this.navigation.stop(); @@ -57,24 +48,36 @@ return InteractionResult.SUCCESS.withoutItem(); } -@@ -499,6 +_,13 @@ +@@ -486,6 +_,25 @@ - DyeColor dyeColor = dyeItem.getDyeColor(); - if (dyeColor != this.getCollarColor()) { + DyeColor color = itemStack.get(DataComponents.DYE); + if (color != null && color != this.getCollarColor()) { + // Paper start - Add EntityDyeEvent and CollarColorable interface -+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) dyeColor.getId()), (org.bukkit.entity.Player) player.getBukkitEntity()); ++ final DyeColor originalColor = color; ++ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) color.getId()), (org.bukkit.entity.Player) player.getBukkitEntity()); + if (!event.callEvent()) { ++ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_COLLAR_COLOR), serverPlayer); ++ } ++ if (!player.hasInfiniteMaterials()) { ++ player.containerMenu.forceHeldSlot(hand); ++ } + return InteractionResult.FAIL; + } -+ dyeColor = DyeColor.byId(event.getColor().getWoolData()); ++ color = DyeColor.byId(event.getColor().getWoolData()); ++ if (originalColor != color) { ++ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_COLLAR_COLOR), serverPlayer); ++ } ++ } + // Paper end - Add EntityDyeEvent and CollarColorable interface - this.setCollarColor(dyeColor); - itemInHand.consume(1, player); + this.setCollarColor(color); + itemStack.consume(1, player); return InteractionResult.SUCCESS; -@@ -513,7 +_,7 @@ +@@ -500,7 +_,7 @@ } - private void tryToTame(Player player) { + private void tryToTame(final Player player) { - if (this.random.nextInt(3) == 0) { + if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call this.tame(player); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch index 89b1a90fe0b4..7900660e9112 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch @@ -6,14 +6,14 @@ public int time; + public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals - public EndCrystal(EntityType type, Level level) { + public EndCrystal(final EntityType type, final Level level) { super(type, level); @@ -57,21 +_,37 @@ if (this.level() instanceof ServerLevel) { - BlockPos blockPos = this.blockPosition(); - if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockPos).isAir()) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos, this).isCancelled()) { // Paper - this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos)); + BlockPos pos = this.blockPosition(); + if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(pos).isAir()) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), pos, this).isCancelled()) { // Paper + this.level().setBlockAndUpdate(pos, BaseFireBlock.getState(this.level(), pos)); - } - } + } // Paper @@ -25,7 +25,7 @@ + if (!java.util.Objects.equals(((ServerLevel) this.level()).uuid, this.originWorld) + || ((ServerLevel) this.level()).getDragonFight() == null + || ((ServerLevel) this.level()).getDragonFight().respawnStage == null -+ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnAnimation.SUMMONING_DRAGON.ordinal()) { ++ || ((ServerLevel) this.level()).getDragonFight().respawnStage.ordinal() > net.minecraft.world.level.dimension.end.DragonRespawnStage.SUMMONING_DRAGON.ordinal()) { + this.setInvulnerable(false); + this.setBeamTarget(null); + } @@ -34,14 +34,14 @@ } @Override - protected void addAdditionalSaveData(ValueOutput output) { + protected void addAdditionalSaveData(final ValueOutput output) { output.storeNullable("beam_target", BlockPos.CODEC, this.getBeamTarget()); output.putBoolean("ShowBottom", this.showsBottom()); + output.putBoolean("Paper.GeneratedByDragonFight", this.generatedByDragonFight); // Paper - Fix invulnerable end crystals } @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { this.setBeamTarget(input.read("beam_target", BlockPos.CODEC).orElse(null)); this.setShowBottom(input.getBooleanOr("ShowBottom", true)); + this.generatedByDragonFight = input.getBooleanOr("Paper.GeneratedByDragonFight", false); // Paper - Fix invulnerable end crystals @@ -54,13 +54,13 @@ if (!this.isRemoved()) { - this.remove(Entity.RemovalReason.KILLED); + // CraftBukkit start - All non-living entities need this -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, false)) { + return false; + } + // CraftBukkit end - if (!damageSource.is(DamageTypeTags.IS_EXPLOSION)) { - DamageSource damageSource1 = damageSource.getEntity() != null ? this.damageSources().explosion(this, damageSource.getEntity()) : null; -- level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); + if (!source.is(DamageTypeTags.IS_EXPLOSION)) { + DamageSource damageSource = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null; +- level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); + // CraftBukkit start + org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); + if (event.isCancelled()) { @@ -68,10 +68,10 @@ + } + + this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // Paper - add Bukkit remove cause -+ level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); ++ level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); + } else { + this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause + // CraftBukkit end } - this.onDestroyedBy(level, damageSource); + this.onDestroyedBy(level, source); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch index 0ccd70609a01..b0259db709df 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -9,7 +9,7 @@ + @Nullable private BlockPos podium; + // Paper end - public EnderDragon(EntityType type, Level level) { + public EnderDragon(final EntityType type, final Level level) { super(EntityType.ENDER_DRAGON, level); @@ -101,6 +_,7 @@ this.setHealth(this.getMaxHealth()); @@ -18,7 +18,7 @@ + this.explosionSource = new net.minecraft.world.level.ServerExplosion(level.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, net.minecraft.world.level.Explosion.BlockInteraction.DESTROY); // Paper } - public void setDragonFight(EndDragonFight dragonFight) { + public void setDragonFight(final EnderDragonFight fight) { @@ -119,6 +_,19 @@ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0).add(Attributes.CAMERA_DISTANCE, 16.0); } @@ -38,16 +38,16 @@ + @Override public boolean isFlapping() { - float cos = Mth.cos(this.flapTime * (float) (Math.PI * 2)); + float flap = Mth.cos(this.flapTime * (float) (Math.PI * 2)); @@ -210,7 +_,7 @@ } - Vec3 flyTargetLocation = currentPhase.getFlyTargetLocation(); -- if (flyTargetLocation != null) { -+ if (flyTargetLocation != null && currentPhase.getPhase() != EnderDragonPhase.HOVERING) { // CraftBukkit - Don't move when hovering - double d = flyTargetLocation.x - this.getX(); - double d1 = flyTargetLocation.y - this.getY(); - double d2 = flyTargetLocation.z - this.getZ(); + Vec3 targetLocation = currentPhase.getFlyTargetLocation(); +- if (targetLocation != null) { ++ if (targetLocation != null && currentPhase.getPhase() != EnderDragonPhase.HOVERING) { // CraftBukkit - Don't move when hovering + double xdd = targetLocation.x - this.getX(); + double ydd = targetLocation.y - this.getY(); + double zdd = targetLocation.z - this.getZ(); @@ -365,7 +_,12 @@ if (this.nearestCrystal.isRemoved()) { this.nearestCrystal = null; @@ -63,98 +63,99 @@ } @@ -395,7 +_,7 @@ - double d2 = entity.getX() - d; - double d3 = entity.getZ() - d1; - double max = Math.max(d2 * d2 + d3 * d3, 0.1); -- entity.push(d2 / max * 4.0, 0.2F, d3 / max * 4.0); -+ entity.push(d2 / max * 4.0, 0.2F, d3 / max * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - if (!this.phaseManager.getCurrentPhase().isSitting() && livingEntity.getLastHurtByMobTimestamp() < entity.tickCount - 2) { + double xd = entity.getX() - xm; + double zd = entity.getZ() - zm; + double dd = Math.max(xd * xd + zd * zd, 0.1); +- entity.push(xd / dd * 4.0, 0.2F, zd / dd * 4.0); ++ entity.push(xd / dd * 4.0, 0.2F, zd / dd * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + if (!this.phaseManager.getCurrentPhase().isSitting() && livingTarget.getLastHurtByMobTimestamp() < entity.tickCount - 2) { DamageSource damageSource = this.damageSources().mobAttack(this); - entity.hurtServer(level, damageSource, 5.0F); + entity.hurtServer(serverLevel, damageSource, 5.0F); @@ -428,6 +_,7 @@ - int floor5 = Mth.floor(box.maxZ); - boolean flag = false; - boolean flag1 = false; + int z1 = Mth.floor(bb.maxZ); + boolean hitWall = false; + boolean destroyedBlock = false; + List destroyedBlocks = new java.util.ArrayList<>(); // Paper - Create a list to hold all the destroyed blocks - for (int i = floor; i <= floor3; i++) { - for (int i1 = floor1; i1 <= floor4; i1++) { + for (int x = x0; x <= x1; x++) { + for (int y = y0; y <= y1; y++) { @@ -436,7 +_,11 @@ - BlockState blockState = level.getBlockState(blockPos); - if (!blockState.isAir() && !blockState.is(BlockTags.DRAGON_TRANSPARENT)) { - if (level.getGameRules().get(GameRules.MOB_GRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) { -- flag1 = level.removeBlock(blockPos, false) || flag1; + BlockState state = level.getBlockState(blockPos); + if (!state.isAir() && !state.is(BlockTags.DRAGON_TRANSPARENT)) { + if (level.getGameRules().get(GameRules.MOB_GRIEFING) && !state.is(BlockTags.DRAGON_IMMUNE)) { +- destroyedBlock = level.removeBlock(blockPos, false) || destroyedBlock; + // CraftBukkit start - Add blocks to list rather than destroying them + //flag1 = level.removeBlock(blockPos, false) || flag1; -+ flag1 = true; ++ destroyedBlock = true; + destroyedBlocks.add(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos)); + // CraftBukkit end } else { - flag = true; + hitWall = true; } -@@ -445,6 +_,58 @@ +@@ -445,6 +_,59 @@ } } + // CraftBukkit start - Set off an EntityExplodeEvent for the dragon exploding all these blocks + // SPIGOT-4882: don't fire event if nothing hit -+ if (!flag1) { -+ return flag; ++ if (!destroyedBlock) { ++ return hitWall; + } + + org.bukkit.event.entity.EntityExplodeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityExplodeEvent(this, destroyedBlocks, 0F, this.explosionSource.getBlockInteraction()); + if (event.isCancelled()) { + // This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down. + // We should consider adding an event extension for it, or perhaps returning true if the event is cancelled. -+ return flag; ++ return hitWall; + } else if (event.getYield() == 0F) { + // Yield zero ==> no drops + for (org.bukkit.block.Block block : event.blockList()) { + this.level().removeBlock(new BlockPos(block.getX(), block.getY(), block.getZ()), false); + } + } else { -+ for (org.bukkit.block.Block block : event.blockList()) { -+ org.bukkit.Material blockType = block.getType(); ++ for (org.bukkit.block.Block b : event.blockList()) { ++ org.bukkit.Material blockType = b.getType(); + if (blockType.isAir()) { + continue; + } + -+ org.bukkit.craftbukkit.block.CraftBlock craftBlock = ((org.bukkit.craftbukkit.block.CraftBlock) block); ++ org.bukkit.craftbukkit.block.CraftBlock craftBlock = ((org.bukkit.craftbukkit.block.CraftBlock) b); + BlockPos pos = craftBlock.getPosition(); ++ net.minecraft.world.level.block.state.BlockState state = craftBlock.getBlockState(); ++ net.minecraft.world.level.block.Block block = state.getBlock(); + -+ net.minecraft.world.level.block.Block nmsBlock = craftBlock.getNMS().getBlock(); -+ if (nmsBlock.dropFromExplosion(this.explosionSource)) { -+ net.minecraft.world.level.block.entity.BlockEntity blockEntity = craftBlock.getNMS().hasBlockEntity() ? this.level().getBlockEntity(pos) : null; ++ if (block.dropFromExplosion(this.explosionSource)) { ++ net.minecraft.world.level.block.entity.BlockEntity blockEntity = state.hasBlockEntity() ? this.level().getBlockEntity(pos) : null; + net.minecraft.world.level.storage.loot.LootParams.Builder builder = new net.minecraft.world.level.storage.loot.LootParams.Builder((ServerLevel) this.level()) + .withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.ORIGIN, Vec3.atCenterOf(pos)) + .withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.TOOL, net.minecraft.world.item.ItemStack.EMPTY) + .withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.EXPLOSION_RADIUS, 1.0F / event.getYield()) + .withOptionalParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.BLOCK_ENTITY, blockEntity); + -+ craftBlock.getNMS().getDrops(builder).forEach((stack) -> { -+ net.minecraft.world.level.block.Block.popResource(this.level(), pos, stack); ++ state.getDrops(builder).forEach((item) -> { ++ net.minecraft.world.level.block.Block.popResource(this.level(), pos, item); + }); -+ craftBlock.getNMS().spawnAfterBreak((ServerLevel) this.level(), pos, net.minecraft.world.item.ItemStack.EMPTY, false); ++ state.spawnAfterBreak((ServerLevel) this.level(), pos, net.minecraft.world.item.ItemStack.EMPTY, false); + } + // Paper start - TNTPrimeEvent + org.bukkit.block.Block tntBlock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level(), pos); + if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.EXPLOSION, explosionSource.getIndirectSourceEntity().getBukkitEntity()).callEvent()) + continue; + // Paper end - TNTPrimeEvent -+ nmsBlock.wasExploded((ServerLevel) this.level(), pos, this.explosionSource); ++ block.wasExploded((ServerLevel) this.level(), pos, this.explosionSource); + + this.level().removeBlock(pos, false); + } + } + // CraftBukkit end + - if (flag1) { - BlockPos blockPos1 = new BlockPos( - floor + this.random.nextInt(floor3 - floor + 1), -@@ -502,7 +_,15 @@ + if (destroyedBlock) { + BlockPos randomPos = new BlockPos( + x0 + this.random.nextInt(x1 - x0 + 1), y0 + this.random.nextInt(y1 - y0 + 1), z0 + this.random.nextInt(z1 - z0 + 1) +@@ -507,7 +_,15 @@ @Override - public void kill(ServerLevel level) { + public void kill(final ServerLevel level) { - this.remove(Entity.RemovalReason.KILLED); + // Paper start - Fire entity death event + this.silentDeath = true; @@ -168,38 +169,38 @@ this.gameEvent(GameEvent.ENTITY_DIE); if (this.dragonFight != null) { this.dragonFight.updateDragon(this); -@@ -524,18 +_,41 @@ - this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + f, this.getY() + 2.0 + f1, this.getZ() + f2, 0.0, 0.0, 0.0); +@@ -529,18 +_,41 @@ + this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + xo, this.getY() + 2.0 + yo, this.getZ() + zo, 0.0, 0.0, 0.0); } + // CraftBukkit start - SPIGOT-2420: Moved up to #getExpReward method + /* - int i = 500; + int xpCount = 500; if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { - i = 12000; + xpCount = 12000; } + */ -+ int i = this.expToDrop; ++ int xpCount = this.expToDrop; + // CraftBukkit end - if (this.level() instanceof ServerLevel serverLevel) { -- if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && serverLevel.getGameRules().get(GameRules.MOB_DROPS)) { -- ExperienceOrb.award(serverLevel, this.position(), Mth.floor(i * 0.08F)); + if (this.level() instanceof ServerLevel level) { +- if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && level.getGameRules().get(GameRules.MOB_DROPS)) { +- ExperienceOrb.award(level, this.position(), Mth.floor(xpCount * 0.08F)); + if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp -+ ExperienceOrb.awardWithDirection(serverLevel, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(i * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.world.entity.EntityReference.get(this.lastHurtByPlayer, this.level(), Player.class), this); // Paper ++ ExperienceOrb.awardWithDirection(level, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(xpCount * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.world.entity.EntityReference.get(this.lastHurtByPlayer, this.level(), Player.class), this); // Paper } if (this.dragonDeathTime == 1 && !this.isSilent()) { -- serverLevel.globalLevelEvent(LevelEvent.SOUND_DRAGON_DEATH, this.blockPosition(), 0); +- level.globalLevelEvent(LevelEvent.SOUND_DRAGON_DEATH, this.blockPosition(), 0); + // CraftBukkit start - Use relative location for far away sounds -+ // serverLevel.globalLevelEvent(LevelEvent.SOUND_DRAGON_DEATH, this.blockPosition(), 0); -+ int viewDistance = serverLevel.getCraftServer().getViewDistance() * 16; -+ for (net.minecraft.server.level.ServerPlayer player : serverLevel.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule ++ // level.globalLevelEvent(LevelEvent.SOUND_DRAGON_DEATH, this.blockPosition(), 0); ++ int viewDistance = level.getCraftServer().getViewDistance() * 16; ++ for (net.minecraft.server.level.ServerPlayer player : level.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule + double deltaX = this.getX() - player.getX(); + double deltaZ = this.getZ() - player.getZ(); + double distanceSquared = Mth.square(deltaX) + Mth.square(deltaZ); -+ final double soundRadiusSquared = serverLevel.getGlobalSoundRangeSquared(config -> config.dragonDeathSoundRadius); // Paper - respect global sound events gamerule -+ if (!serverLevel.getGameRules().get(GameRules.GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Paper - respect global sound events gamerule ++ final double soundRadiusSquared = level.getGlobalSoundRangeSquared(config -> config.dragonDeathSoundRadius); // Paper - respect global sound events gamerule ++ if (!level.getGameRules().get(GameRules.GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Paper - respect global sound events gamerule + if (distanceSquared > Mth.square(viewDistance)) { + double deltaLength = Math.sqrt(distanceSquared); + double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; @@ -213,14 +214,14 @@ } } -@@ -548,15 +_,15 @@ +@@ -553,15 +_,15 @@ } - if (this.dragonDeathTime == 200 && this.level() instanceof ServerLevel serverLevel1) { -- if (serverLevel1.getGameRules().get(GameRules.MOB_DROPS)) { -- ExperienceOrb.award(serverLevel1, this.position(), Mth.floor(i * 0.2F)); + if (this.dragonDeathTime >= 200 && this.level() instanceof ServerLevel level) { +- if (level.getGameRules().get(GameRules.MOB_DROPS)) { +- ExperienceOrb.award(level, this.position(), Mth.floor(xpCount * 0.2F)); + if (true) { // Paper - SPIGOT-2420: Already checked for the game rule when calculating the xp -+ ExperienceOrb.awardWithDirection(serverLevel1, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(i * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.world.entity.EntityReference.get(this.lastHurtByPlayer, this.level(), Player.class), this); // Paper ++ ExperienceOrb.awardWithDirection(level, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(xpCount * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.world.entity.EntityReference.get(this.lastHurtByPlayer, this.level(), Player.class), this); // Paper } if (this.dragonFight != null) { @@ -232,7 +233,7 @@ this.gameEvent(GameEvent.ENTITY_DIE); } } -@@ -737,6 +_,7 @@ +@@ -744,6 +_,7 @@ super.addAdditionalSaveData(output); output.putInt("DragonPhase", this.phaseManager.getCurrentPhase().getPhase().getId()); output.putInt("DragonDeathTime", this.dragonDeathTime); @@ -240,25 +241,25 @@ } @Override -@@ -744,6 +_,7 @@ +@@ -751,6 +_,7 @@ super.readAdditionalSaveData(input); - input.getInt("DragonPhase").ifPresent(integer -> this.phaseManager.setPhase(EnderDragonPhase.getById(integer))); + input.getInt("DragonPhase").ifPresent(phaseId -> this.phaseManager.setPhase(EnderDragonPhase.getById(phaseId))); this.dragonDeathTime = input.getIntOr("DragonDeathTime", 0); + this.expToDrop = input.getIntOr("Bukkit.expToDrop", 0); // CraftBukkit - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts } @Override -@@ -784,7 +_,7 @@ - EnderDragonPhase phase = currentPhase.getPhase(); - Vec3 viewVector; +@@ -791,7 +_,7 @@ + EnderDragonPhase phase = phaseInstance.getPhase(); + Vec3 result; if (phase == EnderDragonPhase.LANDING || phase == EnderDragonPhase.TAKEOFF) { -- BlockPos heightmapPos = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin)); -+ BlockPos heightmapPos = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium - float max = Math.max((float)Math.sqrt(heightmapPos.distToCenterSqr(this.position())) / 4.0F, 1.0F); - float f = 6.0F / max; - float xRot = this.getXRot(); -@@ -871,4 +_,19 @@ - protected float sanitizeScale(float scale) { +- BlockPos egg = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin)); ++ BlockPos egg = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium + float dist = Math.max((float)Math.sqrt(egg.distToCenterSqr(this.position())) / 4.0F, 1.0F); + float yOffset = 6.0F / dist; + float xRotOld = this.getXRot(); +@@ -878,4 +_,19 @@ + protected float sanitizeScale(final float scale) { return 1.0F; } + @@ -266,14 +267,14 @@ + @Override + public int getExpReward(ServerLevel level, Entity entity) { + // CraftBukkit - Moved from #tickDeath method -+ boolean flag = level.getGameRules().get(GameRules.MOB_DROPS); -+ int i = 500; ++ boolean shouldDrop = level.getGameRules().get(GameRules.MOB_DROPS); ++ int xpCount = 500; + + if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { -+ i = 12000; ++ xpCount = 12000; + } + -+ return flag ? i : 0; ++ return shouldDrop ? xpCount : 0; + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java.patch index 50c8b1f6f662..72f7f6dcf6e2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java @@ -33,7 +_,7 @@ - public void doServerTick(ServerLevel level) { + public void doServerTick(final ServerLevel level) { this.time++; if (this.targetLocation == null) { -- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - this.targetLocation = Vec3.atBottomCenterOf(heightmapPos); +- BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + this.targetLocation = Vec3.atBottomCenterOf(egg); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java.patch index 0ae3e07ca1ce..83f37436200a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java @@ -50,7 +_,7 @@ - private void findNewTarget(ServerLevel level) { + private void findNewTarget(final ServerLevel level) { if (this.currentPath != null && this.currentPath.isDone()) { -- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - int i = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().getCrystalsAlive(); - if (this.dragon.getRandom().nextInt(i + 3) == 0) { +- BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + int crystals = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().aliveCrystals(); + if (this.dragon.getRandom().nextInt(crystals + 3) == 0) { this.dragon.getPhaseManager().setPhase(EnderDragonPhase.LANDING_APPROACH); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java.patch index 0abf0d51e715..4821a085de51 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java @@ -49,7 +_,7 @@ - private void findNewTarget(ServerLevel level) { + private void findNewTarget(final ServerLevel level) { if (this.currentPath == null || this.currentPath.isDone()) { - int i = this.dragon.findClosestNode(); -- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - Player nearestPlayer = level.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, heightmapPos.getX(), heightmapPos.getY(), heightmapPos.getZ()); - int i1; - if (nearestPlayer != null) { + int currentNodeIndex = this.dragon.findClosestNode(); +- BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + Player playerNearestToEgg = level.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, egg.getX(), egg.getY(), egg.getZ()); + int targetNodeIndex; + if (playerNearestToEgg != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java.patch index dcadba51268e..12f5d4e4c426 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java @@ -50,7 +_,7 @@ - public void doServerTick(ServerLevel level) { + public void doServerTick(final ServerLevel level) { if (this.targetLocation == null) { this.targetLocation = Vec3.atBottomCenterOf( - level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java.patch index 42a7a0356203..2c15d57ca37d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonSittingFlamingPhase.java -@@ -93,7 +_,13 @@ +@@ -87,7 +_,13 @@ this.flame.setCustomParticle(PowerParticleOption.create(ParticleTypes.DRAGON_BREATH, 1.0F)); this.flame.setPotionDurationScale(0.25F); this.flame.addEffect(new MobEffectInstance(MobEffects.INSTANT_DAMAGE)); @@ -14,7 +14,7 @@ } } -@@ -106,7 +_,7 @@ +@@ -100,7 +_,7 @@ @Override public void end() { if (this.flame != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java.patch index 8a080ca5df82..11838192c528 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java -@@ -70,13 +_,16 @@ - double d6 = this.attackTarget.getY(0.5) - d3; - double d7 = this.attackTarget.getZ() - d4; - Vec3 vec32 = new Vec3(d5, d6, d7); +@@ -72,13 +_,16 @@ + double ydd = this.attackTarget.getY(0.5) - startingY; + double zdd = this.attackTarget.getZ() - startingZ; + Vec3 direction = new Vec3(xdd, ydd, zdd); - if (!this.dragon.isSilent()) { + if (false && !this.dragon.isSilent()) { // Paper - EnderDragon Events; Fire after shoot fireball event level.levelEvent(null, LevelEvent.SOUND_DRAGON_FIREBALL, this.dragon.blockPosition(), 0); } - DragonFireball dragonFireball = new DragonFireball(level, this.dragon, vec32.normalize()); - dragonFireball.snapTo(d2, d3, d4, 0.0F, 0.0F); -+ if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) this.dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events + DragonFireball entity = new DragonFireball(level, this.dragon, direction.normalize()); + entity.snapTo(startingX, startingY, startingZ, 0.0F, 0.0F); ++ if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) this.dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) entity.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events + if (!this.dragon.isSilent()) level.levelEvent(null, LevelEvent.SOUND_DRAGON_FIREBALL, this.dragon.blockPosition(), 0); // Paper - EnderDragon Events; Fire after shoot fireball event - level.addFreshEntity(dragonFireball); -+ } else dragonFireball.discard(null); // Paper - EnderDragon Events + level.addFreshEntity(entity); ++ } else entity.discard(null); // Paper - EnderDragon Events this.fireballCharge = 0; if (this.currentPath != null) { while (!this.currentPath.isDone()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java.patch index f58b95dd48cd..909c55e73f90 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java @@ -22,7 +_,7 @@ @Override - public void doServerTick(ServerLevel level) { + public void doServerTick(final ServerLevel level) { if (!this.firstTick && this.currentPath != null) { -- BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); -+ BlockPos heightmapPos = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium - if (!heightmapPos.closerToCenterThan(this.dragon.position(), 10.0)) { +- BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin())); ++ BlockPos egg = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium + if (!egg.closerToCenterThan(this.dragon.position(), 10.0)) { this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch index 41396fd6331f..7024e32b5783 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch @@ -1,21 +1,27 @@ --- a/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java +++ b/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java -@@ -23,6 +_,18 @@ +@@ -17,11 +_,23 @@ + this.setPhase(EnderDragonPhase.HOVERING); + } + +- public void setPhase(final EnderDragonPhase target) { ++ public void setPhase(EnderDragonPhase target) { // CraftBukkit - Call EnderDragonChangePhaseEvent + if (this.currentPhase == null || target != this.currentPhase.getPhase()) { + if (this.currentPhase != null) { this.currentPhase.end(); } - ++ + // CraftBukkit start - Call EnderDragonChangePhaseEvent + org.bukkit.event.entity.EnderDragonChangePhaseEvent event = new org.bukkit.event.entity.EnderDragonChangePhaseEvent( + (org.bukkit.craftbukkit.entity.CraftEnderDragon) this.dragon.getBukkitEntity(), + (this.currentPhase == null) ? null : org.bukkit.craftbukkit.entity.CraftEnderDragon.getBukkitPhase(this.currentPhase.getPhase()), -+ org.bukkit.craftbukkit.entity.CraftEnderDragon.getBukkitPhase(phase) ++ org.bukkit.craftbukkit.entity.CraftEnderDragon.getBukkitPhase(target) + ); + if (!event.callEvent()) { + return; + } -+ phase = org.bukkit.craftbukkit.entity.CraftEnderDragon.getMinecraftPhase(event.getNewPhase()); ++ target = org.bukkit.craftbukkit.entity.CraftEnderDragon.getMinecraftPhase(event.getNewPhase()); + // CraftBukkit end -+ - this.currentPhase = this.getPhase((EnderDragonPhase)phase); + + this.currentPhase = this.getPhase((EnderDragonPhase)target); if (!this.dragon.level().isClientSide()) { - this.dragon.getEntityData().set(EnderDragon.DATA_PHASE, phase.getId()); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index fd3e6fe6529c..ecb892c4f6a5 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -72,6 +_,7 @@ +@@ -74,6 +_,7 @@ private final int[] nextHeadUpdate = new int[2]; private final int[] idleHeadUpdates = new int[2]; private int destroyBlocksTick; + private boolean canPortal = false; // Paper - public final ServerBossEvent bossEvent = (ServerBossEvent)new ServerBossEvent( - this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS - ) -@@ -263,15 +_,40 @@ - int i = this.getInvulnerableTicks() - 1; - this.bossEvent.setProgress(1.0F - i / 220.0F); - if (i <= 0) { + public final ServerBossEvent bossEvent = Util.make( + new ServerBossEvent(Mth.createInsecureUUID(this.random), this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS), + e -> e.setDarkenScreen(true) +@@ -265,15 +_,40 @@ + int newCount = this.getInvulnerableTicks() - 1; + this.bossEvent.setProgress(1.0F - newCount / 220.0F); + if (newCount <= 0) { - level.explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, Level.ExplosionInteraction.MOB); + // CraftBukkit start + org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); @@ -45,34 +45,34 @@ } } - this.setInvulnerableTicks(i); + this.setInvulnerableTicks(newCount); if (this.tickCount % 10 == 0) { - this.heal(10.0F); + this.heal(10.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit } } else { super.customServerAiStep(level); -@@ -308,6 +_,7 @@ +@@ -307,6 +_,7 @@ ); - if (!nearbyEntities.isEmpty()) { - LivingEntity livingEntity1 = nearbyEntities.get(this.random.nextInt(nearbyEntities.size())); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this, livingEntity1, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit - this.setAlternativeTarget(ix, livingEntity1.getId()); + if (!entities.isEmpty()) { + LivingEntity selected = entities.get(this.random.nextInt(entities.size())); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this, selected, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit + this.setAlternativeTarget(i, selected.getId()); } } -@@ -337,6 +_,11 @@ +@@ -336,6 +_,11 @@ )) { - BlockState blockState = level.getBlockState(blockPos); - if (canDestroy(blockState)) { + BlockState state = level.getBlockState(blockPos); + if (canDestroy(state)) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end - flag = level.destroyBlock(blockPos, true, this) || flag; + destroyed = level.destroyBlock(blockPos, true, this) || destroyed; } } -@@ -348,7 +_,7 @@ +@@ -347,7 +_,7 @@ } if (this.tickCount % 20 == 0) { @@ -81,15 +81,15 @@ } this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); -@@ -486,16 +_,16 @@ +@@ -485,16 +_,16 @@ @Override - protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { - super.dropCustomDeathLoot(level, damageSource, recentlyHit); -- ItemEntity itemEntity = this.spawnAtLocation(level, Items.NETHER_STAR); -+ ItemEntity itemEntity = this.spawnAtLocation(level, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), net.minecraft.world.phys.Vec3.ZERO, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer - if (itemEntity != null) { -- itemEntity.setExtendedLifetime(); -+ itemEntity.setExtendedLifetime(); // Paper - diff on change + protected void dropCustomDeathLoot(final ServerLevel level, final DamageSource source, final boolean killedByPlayer) { + super.dropCustomDeathLoot(level, source, killedByPlayer); +- ItemEntity netherStar = this.spawnAtLocation(level, Items.NETHER_STAR); ++ ItemEntity netherStar = this.spawnAtLocation(level, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), net.minecraft.world.phys.Vec3.ZERO, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer + if (netherStar != null) { +- netherStar.setExtendedLifetime(); ++ netherStar.setExtendedLifetime(); // Paper - diff on change } } @@ -102,10 +102,10 @@ } else { this.noActionTime = 0; } -@@ -550,12 +_,18 @@ +@@ -549,12 +_,18 @@ @Override - public boolean canUsePortal(boolean allowPassengers) { + public boolean canUsePortal(final boolean ignorePassenger) { - return false; - } + return this.canPortal; // Paper @@ -118,9 +118,9 @@ + // Paper end @Override - public boolean canBeAffected(MobEffectInstance effectInstance) { -- return !effectInstance.is(MobEffects.WITHER) && super.canBeAffected(effectInstance); -+ return (!effectInstance.is(MobEffects.WITHER) || !this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither) && super.canBeAffected(effectInstance); + public boolean canBeAffected(final MobEffectInstance newEffect) { +- return !newEffect.is(MobEffects.WITHER) && super.canBeAffected(newEffect); ++ return (!newEffect.is(MobEffects.WITHER) || !this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.wither) && super.canBeAffected(newEffect); } - class WitherDoNothingGoal extends Goal { + private class WitherDoNothingGoal extends Goal { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch index 8e6296c6ae5b..8a895d311c68 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -86,9 +_,16 @@ +@@ -88,9 +_,16 @@ private boolean invisible = false; public long lastHit; public int disabledSlots = 0; @@ -11,13 +11,13 @@ + private boolean noTickEquipmentDirty = false; + // Paper end - Allow ArmorStands not to tick - public ArmorStand(EntityType type, Level level) { + public ArmorStand(final EntityType type, final Level level) { super(type, level); + if (level != null) this.canTick = level.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick } - public ArmorStand(Level level, double x, double y, double z) { -@@ -100,6 +_,13 @@ + public ArmorStand(final Level level, final double x, final double y, final double z) { +@@ -102,6 +_,13 @@ return createLivingAttributes().add(Attributes.STEP_HEIGHT, 0.0); } @@ -30,23 +30,23 @@ + @Override public void refreshDimensions() { - double x = this.getX(); -@@ -135,6 +_,14 @@ + double oldX = this.getX(); +@@ -137,6 +_,14 @@ return slot != EquipmentSlot.BODY && slot != EquipmentSlot.SADDLE && !this.isDisabled(slot); } -+ // Paper - Allow ArmorStands not to tick; Still update equipment ++ // Paper start - Allow ArmorStands not to tick; Still update equipment + @Override -+ public void setItemSlot(net.minecraft.world.entity.EquipmentSlot slot, ItemStack stack, boolean silent) { ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { + super.setItemSlot(slot, stack, silent); + this.noTickEquipmentDirty = true; + } -+ // Paper - Allow ArmorStands not to tick; Still update equipment ++ // Paper end - Allow ArmorStands not to tick; Still update equipment + @Override - protected void addAdditionalSaveData(ValueOutput output) { + protected void addAdditionalSaveData(final ValueOutput output) { super.addAdditionalSaveData(output); -@@ -148,6 +_,7 @@ +@@ -150,6 +_,7 @@ } output.store("Pose", ArmorStand.ArmorStandPose.CODEC, this.getArmorStandPose()); @@ -54,7 +54,7 @@ } @Override -@@ -161,10 +_,16 @@ +@@ -163,10 +_,16 @@ this.setMarker(input.getBooleanOr("Marker", false)); this.noPhysics = !this.hasPhysics(); input.read("Pose", ArmorStand.ArmorStandPose.CODEC).ifPresent(this::setArmorStandPose); @@ -72,7 +72,7 @@ return false; } -@@ -174,6 +_,7 @@ +@@ -176,6 +_,7 @@ @Override protected void pushEntities() { @@ -80,155 +80,147 @@ for (Entity entity : this.level().getEntities(this, this.getBoundingBox(), RIDABLE_MINECARTS)) { if (this.distanceToSqr(entity) <= 0.2) { entity.push(this); -@@ -246,7 +_,25 @@ +@@ -248,7 +_,25 @@ return false; - } else if (itemBySlot.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(16)) != 0) { + } else if (itemStack.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(16)) != 0) { return false; -- } else if (player.hasInfiniteMaterials() && itemBySlot.isEmpty() && !stack.isEmpty()) { -+ // CraftBukkit start -+ } else { -+ org.bukkit.inventory.ItemStack armorStandItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemBySlot); -+ org.bukkit.inventory.ItemStack playerHeldItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack); +- } else if (player.hasInfiniteMaterials() && itemStack.isEmpty() && !playerItemStack.isEmpty()) { ++ } + -+ org.bukkit.entity.Player player1 = (org.bukkit.entity.Player) player.getBukkitEntity(); -+ org.bukkit.entity.ArmorStand self = (org.bukkit.entity.ArmorStand) this.getBukkitEntity(); ++ // CraftBukkit start ++ org.bukkit.inventory.ItemStack armorStandItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); ++ org.bukkit.inventory.ItemStack playerHeldItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(playerItemStack); + -+ org.bukkit.inventory.EquipmentSlot slot1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot); -+ org.bukkit.inventory.EquipmentSlot hand1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); -+ org.bukkit.event.player.PlayerArmorStandManipulateEvent armorStandManipulateEvent = new org.bukkit.event.player.PlayerArmorStandManipulateEvent(player1, self, playerHeldItem, armorStandItem, slot1, hand1); -+ this.level().getCraftServer().getPluginManager().callEvent(armorStandManipulateEvent); ++ org.bukkit.entity.Player player1 = (org.bukkit.entity.Player) player.getBukkitEntity(); ++ org.bukkit.entity.ArmorStand self = (org.bukkit.entity.ArmorStand) this.getBukkitEntity(); + -+ if (armorStandManipulateEvent.isCancelled()) { -+ return true; -+ } ++ org.bukkit.inventory.EquipmentSlot slot1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot); ++ org.bukkit.inventory.EquipmentSlot hand1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); ++ org.bukkit.event.player.PlayerArmorStandManipulateEvent armorStandManipulateEvent = new org.bukkit.event.player.PlayerArmorStandManipulateEvent(player1, self, playerHeldItem, armorStandItem, slot1, hand1); ++ this.level().getCraftServer().getPluginManager().callEvent(armorStandManipulateEvent); + -+ if (player.hasInfiniteMaterials() && itemBySlot.isEmpty() && !stack.isEmpty()) { -+ // CraftBukkit end - this.setItemSlot(slot, stack.copyWithCount(1)); - return true; - } else if (stack.isEmpty() || stack.getCount() <= 1) { -@@ -259,6 +_,7 @@ - this.setItemSlot(slot, stack.split(1)); ++ if (armorStandManipulateEvent.isCancelled()) { ++ return true; ++ } ++ // CraftBukkit end ++ if (player.hasInfiniteMaterials() && itemStack.isEmpty() && !playerItemStack.isEmpty()) { + this.setItemSlot(slot, playerItemStack.copyWithCount(1)); return true; - } -+ } // CraftBukkit - } - - @Override -@@ -268,15 +_,32 @@ - } else if (!level.getGameRules().get(GameRules.MOB_GRIEFING) && damageSource.getEntity() instanceof Mob) { + } else if (playerItemStack.isEmpty() || playerItemStack.getCount() <= 1) { +@@ -270,15 +_,32 @@ + } else if (!level.getGameRules().get(GameRules.MOB_GRIEFING) && source.getEntity() instanceof Mob) { return false; - } else if (damageSource.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { + } else if (source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { - this.kill(level); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage)) { + return false; + } -+ this.kill(level, damageSource); // CraftBukkit ++ this.kill(level, source); // CraftBukkit + // CraftBukkit end return false; -- } else if (this.isInvulnerableTo(level, damageSource) || this.invisible || this.isMarker()) { -+ } else if (this.isInvulnerableTo(level, damageSource) /*|| this.invisible*/ || this.isMarker()) { // CraftBukkit +- } else if (this.isInvulnerableTo(level, source) || this.invisible || this.isMarker()) { ++ } else if (this.isInvulnerableTo(level, source) /*|| this.invisible*/ || this.isMarker()) { // CraftBukkit return false; - } else if (damageSource.is(DamageTypeTags.IS_EXPLOSION)) { -- this.brokenByAnything(level, damageSource); + } else if (source.is(DamageTypeTags.IS_EXPLOSION)) { +- this.brokenByAnything(level, source); - this.kill(level); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, true, this.invisible)) { + return false; + } + // CraftBukkit end + // Paper start - avoid duplicate event call -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, damageSource); -+ if (!event.isCancelled()) this.kill(level, damageSource, false); // CraftBukkit ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, source); ++ if (!event.isCancelled()) this.kill(level, source, false); // CraftBukkit + // Paper end return false; - } else if (damageSource.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, true, this.invisible)) { + return false; + } + // CraftBukkit end if (this.isOnFire()) { - this.causeDamage(level, damageSource, 0.15F); + this.causeDamage(level, source, 0.15F); } else { -@@ -285,9 +_,19 @@ +@@ -287,9 +_,19 @@ return false; - } else if (damageSource.is(DamageTypeTags.BURNS_ARMOR_STANDS) && this.getHealth() > 0.5F) { + } else if (source.is(DamageTypeTags.BURNS_ARMOR_STANDS) && this.getHealth() > 0.5F) { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, true, this.invisible)) { + return false; + } + // CraftBukkit end - this.causeDamage(level, damageSource, 4.0F); + this.causeDamage(level, source, 4.0F); return false; } else { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, true, this.invisible)) { + return false; + } + // CraftBukkit end - boolean isCanBreakArmorStand = damageSource.is(DamageTypeTags.CAN_BREAK_ARMOR_STAND); - boolean isAlwaysKillsArmorStands = damageSource.is(DamageTypeTags.ALWAYS_KILLS_ARMOR_STANDS); - if (!isCanBreakArmorStand && !isAlwaysKillsArmorStands) { -@@ -297,7 +_,7 @@ - } else if (damageSource.isCreativePlayer()) { + boolean allowIncrementalBreaking = source.is(DamageTypeTags.CAN_BREAK_ARMOR_STAND); + boolean shouldKill = source.is(DamageTypeTags.ALWAYS_KILLS_ARMOR_STANDS); + if (!allowIncrementalBreaking && !shouldKill) { +@@ -299,7 +_,7 @@ + } else if (source.isCreativePlayer()) { this.playBrokenSound(); this.showBreakingParticles(); - this.kill(level); -+ this.kill(level, damageSource); // CraftBukkit ++ this.kill(level, source); // CraftBukkit return true; } else { - long gameTime = level.getGameTime(); -@@ -306,9 +_,9 @@ - this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); - this.lastHit = gameTime; + long time = level.getGameTime(); +@@ -308,9 +_,9 @@ + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); + this.lastHit = time; } else { -- this.brokenByPlayer(level, damageSource); -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(level, damageSource); // Paper +- this.brokenByPlayer(level, source); ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(level, source); // Paper this.showBreakingParticles(); - this.kill(level); -+ if (!event.isCancelled()) this.kill(level, damageSource, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) ++ if (!event.isCancelled()) this.kill(level, source, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) } return true; -@@ -360,31 +_,42 @@ +@@ -362,31 +_,42 @@ float health = this.getHealth(); - health -= damageAmount; + health -= dmg; if (health <= 0.5F) { -- this.brokenByAnything(level, damageSource); +- this.brokenByAnything(level, source); - this.kill(level); + // Paper start - avoid duplicate event call -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, damageSource); -+ if (!event.isCancelled()) this.kill(level, damageSource, false); // CraftBukkit ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, source); ++ if (!event.isCancelled()) this.kill(level, source, false); // CraftBukkit + // Paper end } else { this.setHealth(health); - this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); } } -- private void brokenByPlayer(ServerLevel level, DamageSource damageSource) { -+ private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel level, DamageSource damageSource) { // Paper - ItemStack itemStack = new ItemStack(Items.ARMOR_STAND); - itemStack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); -- Block.popResource(this.level(), this.blockPosition(), itemStack); -- this.brokenByAnything(level, damageSource); -+ this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior -+ return this.brokenByAnything(level, damageSource); // Paper +- private void brokenByPlayer(final ServerLevel level, final DamageSource source) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(final ServerLevel level, final DamageSource source) { // Paper + ItemStack result = new ItemStack(Items.ARMOR_STAND); + result.set(DataComponents.CUSTOM_NAME, this.getCustomName()); +- Block.popResource(this.level(), this.blockPosition(), result); +- this.brokenByAnything(level, source); ++ this.drops.add(new DefaultDrop(result, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior ++ return this.brokenByAnything(level, source); // Paper } -- private void brokenByAnything(ServerLevel level, DamageSource damageSource) { -+ private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(ServerLevel level, DamageSource damageSource) { // Paper +- private void brokenByAnything(final ServerLevel level, final DamageSource source) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(final ServerLevel level, final DamageSource source) { // Paper this.playBrokenSound(); -- this.dropAllDeathLoot(level, damageSource); -+ // this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved down +- this.dropAllDeathLoot(level, source); ++ // this.dropAllDeathLoot(level, source); // CraftBukkit - moved down - for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) { -- ItemStack itemStack = this.equipment.set(equipmentSlot, ItemStack.EMPTY); -+ ItemStack itemStack = this.equipment.get(equipmentSlot); // Paper - move equipment removal past event call - if (!itemStack.isEmpty()) { + for (EquipmentSlot slot : EquipmentSlot.VALUES) { +- ItemStack itemStack = this.equipment.set(slot, ItemStack.EMPTY); ++ ItemStack itemStack = this.equipment.get(slot); // Paper - move equipment removal past event call + if (!itemStack.isEmpty() && !EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) { - Block.popResource(this.level(), this.blockPosition().above(), itemStack); - } - } @@ -236,10 +228,10 @@ + } + } + // Paper start - move equipment removal past event call -+ org.bukkit.event.entity.EntityDeathEvent event = this.dropAllDeathLoot(level, damageSource); ++ org.bukkit.event.entity.EntityDeathEvent event = this.dropAllDeathLoot(level, source); + if (!event.isCancelled()) { -+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) { -+ this.equipment.set(equipmentSlot, ItemStack.EMPTY); ++ for (EquipmentSlot slot : EquipmentSlot.VALUES) { ++ this.equipment.set(slot, ItemStack.EMPTY); + } + } + return event; @@ -247,7 +239,7 @@ } private void playBrokenSound() { -@@ -432,9 +_,40 @@ +@@ -434,9 +_,40 @@ return this.isSmall(); } @@ -267,20 +259,20 @@ + // Paper end - Allow ArmorStands not to tick + @Override - public void kill(ServerLevel level) { + public void kill(final ServerLevel level) { - this.remove(Entity.RemovalReason.KILLED); + // CraftBukkit start - pass DamageSource for kill + this.kill(level, null); + } + -+ public void kill(ServerLevel level, @Nullable DamageSource damageSource) { ++ public void kill(final ServerLevel level, @Nullable final DamageSource source) { + // Paper start - make cancellable -+ this.kill(level, damageSource, true); ++ this.kill(level, source, true); + } + -+ public void kill(ServerLevel level, @Nullable DamageSource damageSource, boolean callEvent) { ++ public void kill(final ServerLevel level, @Nullable final DamageSource source, final boolean callEvent) { + if (callEvent) { -+ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (damageSource == null ? this.damageSources().genericKill() : damageSource), this.drops); // CraftBukkit - call event ++ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (source == null ? this.damageSources().genericKill() : source), this.drops); // CraftBukkit - call event + if (event.isCancelled()) return; + } + // Paper end @@ -290,7 +282,7 @@ } @@ -683,4 +_,13 @@ - .apply(instance, ArmorStand.ArmorStandPose::new) + .apply(i, ArmorStand.ArmorStandPose::new) ); } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch index 85ea8f71868c..c5fbc04fd63a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch @@ -8,10 +8,10 @@ + private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking protected BlockPos pos; - protected BlockAttachedEntity(EntityType type, Level level) { + protected BlockAttachedEntity(final EntityType type, final Level level) { @@ -39,10 +_,26 @@ public void tick() { - if (this.level() instanceof ServerLevel serverLevel) { + if (this.level() instanceof ServerLevel level) { this.checkBelowWorld(); - if (this.checkInterval++ == 100) { + if (this.checkInterval++ == this.level().spigotConfig.hangingTickFrequency) { // Spigot @@ -35,7 +35,7 @@ + } + // CraftBukkit end + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause - this.dropItem(serverLevel, null); + this.dropItem(level, null); } } @@ -75,6 +_,21 @@ @@ -43,12 +43,12 @@ } else { if (!this.isRemoved()) { + // CraftBukkit start - fire break events -+ Entity damager = (!damageSource.isDirect() && damageSource.getEntity() != null) ? damageSource.getEntity() : damageSource.getDirectEntity(); // Paper - fix DamageSource API ++ Entity damager = (!source.isDirect() && source.getEntity() != null) ? source.getEntity() : source.getDirectEntity(); // Paper - fix DamageSource API + org.bukkit.event.hanging.HangingBreakEvent event; + if (damager != null) { -+ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), damageSource.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.ENTITY); ++ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.ENTITY); + } else { -+ event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damageSource.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.DEFAULT); ++ event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.DEFAULT); + } + + this.level().getCraftServer().getPluginManager().callEvent(event); @@ -59,21 +59,21 @@ + // CraftBukkit end this.kill(level); this.markHurt(); - this.dropItem(level, damageSource.getEntity()); + this.dropItem(level, source.getEntity()); @@ -93,18 +_,36 @@ @Override - public void move(MoverType type, Vec3 movement) { - if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && movement.lengthSqr() > 0.0) { -- this.kill(serverLevel); -- this.dropItem(serverLevel, null); + public void move(final MoverType moverType, final Vec3 delta) { + if (this.level() instanceof ServerLevel level && !this.isRemoved() && delta.lengthSqr() > 0.0) { +- this.kill(level); +- this.dropItem(level, null); - } - } - - @Override -- public void push(double x, double y, double z) { -- if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && x * x + y * y + z * z > 0.0) { -- this.kill(serverLevel); -- this.dropItem(serverLevel, null); +- public void push(final double xa, final double ya, final double za) { +- if (this.level() instanceof ServerLevel level && !this.isRemoved() && xa * xa + ya * ya + za * za > 0.0) { +- this.kill(level); +- this.dropItem(level, null); - } - } + // CraftBukkit start - fire break events @@ -85,16 +85,16 @@ + return; + } + // CraftBukkit end -+ this.kill(serverLevel); -+ this.dropItem(serverLevel, null); ++ this.kill(level); ++ this.dropItem(level, null); + } + } + + @Override -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - override correct overload -+ if (false && this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && x * x + y * y + z * z > 0.0) { // CraftBukkit - not needed -+ this.kill(serverLevel); -+ this.dropItem(serverLevel, null); ++ public void push(final double xa, final double ya, final double za, @Nullable final Entity pushingEntity) { // Paper - override correct overload ++ if (false && this.level() instanceof ServerLevel level && !this.isRemoved() && xa * xa + ya * ya + za * za > 0.0) { // CraftBukkit - not needed ++ this.kill(level); ++ this.dropItem(level, null); + } + } + @@ -108,4 +108,4 @@ + // CraftBukkit end @Override - protected void addAdditionalSaveData(ValueOutput output) { + protected void addAdditionalSaveData(final ValueOutput output) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch index dc67cbaad527..4af212abab10 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch @@ -6,52 +6,52 @@ public boolean fixed = false; + public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames - public ItemFrame(EntityType type, Level level) { + public ItemFrame(final EntityType type, final Level level) { super(type, level); @@ -111,6 +_,11 @@ } - private AABB createBoundingBox(BlockPos pos, Direction direction, boolean hasFramedMap) { + private AABB createBoundingBox(final BlockPos blockPos, final Direction direction, final boolean hasFramedMap) { + // Paper start - add static method -+ return createBoundingBoxStatic(pos, direction, hasFramedMap); ++ return createBoundingBoxStatic(blockPos, direction, hasFramedMap); + } -+ public static AABB createBoundingBoxStatic(BlockPos pos, Direction direction, boolean hasFramedMap) { ++ public static AABB createBoundingBoxStatic(BlockPos blockPos, Direction direction, boolean hasFramedMap) { + // Paper end - add static method - float f = 0.46875F; - Vec3 vec3 = Vec3.atCenterOf(pos).relative(direction, -0.46875); - float f1 = hasFramedMap ? 1.0F : 0.75F; + float shiftToBlockWall = 0.46875F; + Vec3 position = Vec3.atCenterOf(blockPos).relative(direction, -0.46875); + float width = hasFramedMap ? 1.0F : 0.75F; @@ -142,9 +_,9 @@ } @Override -- public void push(double x, double y, double z) { -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param +- public void push(final double xa, final double ya, final double za) { ++ public void push(final double xa, final double ya, final double za, @Nullable Entity pushingEntity) { // Paper - add push source entity param if (!this.fixed) { -- super.push(x, y, z); -+ super.push(x, y, z, pushingEntity); // Paper - add push source entity param +- super.push(xa, ya, za); ++ super.push(xa, ya, za, pushingEntity); // Paper - add push source entity param } } @@ -173,6 +_,18 @@ - if (this.isInvulnerableToBase(damageSource)) { + if (this.isInvulnerableToBase(source)) { return false; - } else if (this.shouldDamageDropItem(damageSource)) { + } else if (this.shouldDamageDropItem(source)) { + // CraftBukkit start - fire EntityDamageEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false) || this.isRemoved()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, false) || this.isRemoved()) { + return true; + } + // CraftBukkit end + // Paper start - Add PlayerItemFrameChangeEvent -+ if (damageSource.getEntity() instanceof Player player) { ++ if (source.getEntity() instanceof Player player) { + var event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE); + if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change + this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false); + } + // Paper end - Add PlayerItemFrameChangeEvent - this.dropItem(level, damageSource.getEntity(), false); - this.gameEvent(GameEvent.BLOCK_CHANGE, damageSource.getEntity()); + this.dropItem(level, source.getEntity(), false); + this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity()); this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); -@@ -258,6 +_,13 @@ +@@ -256,6 +_,13 @@ return this.getEntityData().get(DATA_ITEM); } @@ -62,54 +62,54 @@ + } + // Paper end + - public @Nullable MapId getFramedMapId(ItemStack stack) { - return stack.get(DataComponents.MAP_ID); + public @Nullable MapId getFramedMapId(final ItemStack itemStack) { + return itemStack.get(DataComponents.MAP_ID); } -@@ -271,13 +_,19 @@ +@@ -269,13 +_,19 @@ } - public void setItem(ItemStack stack, boolean updateNeighbours) { + public void setItem(ItemStack itemStack, final boolean updateNeighbours) { + // CraftBukkit start -+ this.setItem(stack, updateNeighbours, true); ++ this.setItem(itemStack, updateNeighbours, true); + } + -+ public void setItem(ItemStack stack, boolean updateNeighbours, boolean playSound) { ++ public void setItem(ItemStack itemStack, final boolean updateNeighbours, boolean playSound) { + // CraftBukkit end - if (!stack.isEmpty()) { - stack = stack.copyWithCount(1); + if (!itemStack.isEmpty()) { + itemStack = itemStack.copyWithCount(1); } - this.onItemChanged(stack); - this.getEntityData().set(DATA_ITEM, stack); -- if (!stack.isEmpty()) { -+ if (!stack.isEmpty() && updateNeighbours && playSound) { // CraftBukkit // Paper - only play sound when update flag is set + this.onItemChanged(itemStack); + this.getEntityData().set(DATA_ITEM, itemStack); +- if (!itemStack.isEmpty()) { ++ if (!itemStack.isEmpty() && updateNeighbours && playSound) { // CraftBukkit // Paper - only play sound when update flag is set this.playSound(this.getAddItemSound(), 1.0F, 1.0F); } -@@ -304,6 +_,7 @@ +@@ -302,6 +_,7 @@ } - private void onItemChanged(ItemStack item) { + private void onItemChanged(final ItemStack item) { + this.cachedMapId = item.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames - if (!item.isEmpty() && item.getFrame() != this) { - item.setEntityRepresentation(this); - } -@@ -372,7 +_,13 @@ - if (savedData != null && savedData.isTrackedCountOverLimit(256)) { + this.recalculateBoundingBox(); + } + +@@ -366,7 +_,13 @@ + if (data != null && data.isTrackedCountOverLimit(256)) { return InteractionResult.FAIL; } else { -- this.setItem(itemInHand); +- this.setItem(itemStack); + // Paper start - Add PlayerItemFrameChangeEvent -+ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemInHand.asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); ++ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemStack.asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); + if (!event.callEvent()) { + return InteractionResult.FAIL; + } + this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); + // Paper end - Add PlayerItemFrameChangeEvent this.gameEvent(GameEvent.BLOCK_CHANGE, player); - itemInHand.consume(1, player); + itemStack.consume(1, player); return InteractionResult.SUCCESS; -@@ -381,6 +_,13 @@ +@@ -375,6 +_,13 @@ return InteractionResult.PASS; } } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch index f89a67b2afb9..de163b618697 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch @@ -1,51 +1,29 @@ --- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -@@ -82,7 +_,7 @@ - boolean flag = false; +@@ -85,7 +_,7 @@ + boolean attachedMob = false; for (Leashable leashable : Leashable.leashableLeashedTo(player)) { - if (leashable.canHaveALeashAttachedTo(this)) { + if (leashable.canHaveALeashAttachedTo(this) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, this, player, hand)) { // Paper - leash event leashable.setLeashedTo(this, true); - flag = true; + attachedMob = true; } -@@ -91,7 +_,7 @@ - boolean flag1 = false; - if (!flag && !player.isSecondaryUseActive()) { - for (Leashable leashable1 : Leashable.leashableLeashedTo(this)) { -- if (leashable1.canHaveALeashAttachedTo(player)) { -+ if (leashable1.canHaveALeashAttachedTo(player) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable1, player, player, hand)) { // Paper - leash event - leashable1.setLeashedTo(player, true); - flag1 = true; +@@ -94,7 +_,7 @@ + boolean anyDropped = false; + if (!attachedMob && !player.isSecondaryUseActive()) { + for (Leashable mob : Leashable.leashableLeashedTo(this)) { +- if (mob.canHaveALeashAttachedTo(player)) { ++ if (mob.canHaveALeashAttachedTo(player) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(mob, player, player, hand)) { // Paper - leash event + mob.setLeashedTo(player, true); + anyDropped = true; } -@@ -111,7 +_,7 @@ +@@ -114,7 +_,7 @@ @Override - public void notifyLeasheeRemoved(Leashable leashHolder) { + public void notifyLeasheeRemoved(final Leashable entity) { if (Leashable.leashableLeashedTo(this).isEmpty()) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause } } -@@ -120,7 +_,12 @@ - return this.level().getBlockState(this.pos).is(BlockTags.FENCES); - } - -+ // Paper start - Track if a knot was created - public static LeashFenceKnotEntity getOrCreateKnot(Level level, BlockPos pos) { -+ return getOrCreateKnot(level, pos, null); -+ } -+ public static LeashFenceKnotEntity getOrCreateKnot(Level level, BlockPos pos, org.apache.commons.lang3.mutable.@Nullable MutableBoolean created) { -+ // Paper end - Track if a knot was created - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); -@@ -134,7 +_,7 @@ - } - - LeashFenceKnotEntity leashFenceKnotEntity1 = new LeashFenceKnotEntity(level, pos); -- level.addFreshEntity(leashFenceKnotEntity1); -+ if (level.addFreshEntity(leashFenceKnotEntity1) && created != null) { created.setTrue(); } // Paper - Track if a knot was created - return leashFenceKnotEntity1; - } - diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/Mannequin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/Mannequin.java.patch index 4fe03af5443c..8b0c9da412b1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/Mannequin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/Mannequin.java.patch @@ -3,7 +3,7 @@ @@ -33,7 +_,7 @@ Mannequin.class, EntityDataSerializers.OPTIONAL_COMPONENT ); - public static final byte ALL_LAYERS = (byte)Arrays.stream(PlayerModelPart.values()).mapToInt(PlayerModelPart::getMask).reduce(0, (i, i1) -> i | i1); + public static final byte ALL_LAYERS = (byte)Arrays.stream(PlayerModelPart.values()).mapToInt(PlayerModelPart::getMask).reduce(0, (a, b) -> a | b); - private static final Set VALID_POSES = Set.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING, Pose.FALL_FLYING, Pose.SLEEPING); + public static final Set VALID_POSES = Set.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING, Pose.FALL_FLYING, Pose.SLEEPING); // Paper - public public static final Codec POSE_CODEC = Pose.CODEC diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/painting/Painting.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/painting/Painting.java.patch index d7108d5cf4ec..07d6a2cb048e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/painting/Painting.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/painting/Painting.java.patch @@ -3,39 +3,39 @@ @@ -149,21 +_,31 @@ @Override - protected AABB calculateBoundingBox(BlockPos pos, Direction direction) { + protected AABB calculateBoundingBox(final BlockPos pos, final Direction direction) { + // CraftBukkit start + PaintingVariant variant = (PaintingVariant) this.getVariant().value(); + return Painting.calculateBoundingBoxStatic(pos, direction, variant.width(), variant.height()); + } + -+ public static AABB calculateBoundingBoxStatic(BlockPos pos, Direction direction, int width, int height) { ++ public static AABB calculateBoundingBoxStatic(final BlockPos pos, final Direction direction, final int width, final int height) { + // CraftBukkit end - float f = 0.46875F; - Vec3 vec3 = Vec3.atCenterOf(pos).relative(direction, -0.46875); -- PaintingVariant paintingVariant = this.getVariant().value(); -- double d = this.offsetForPaintingSize(paintingVariant.width()); -- double d1 = this.offsetForPaintingSize(paintingVariant.height()); + float shiftToBlockWall = 0.46875F; + Vec3 attachedToWall = Vec3.atCenterOf(pos).relative(direction, -0.46875); +- PaintingVariant variant = this.getVariant().value(); +- double horizontalOffset = this.offsetForPaintingSize(variant.width()); +- double verticalOffset = this.offsetForPaintingSize(variant.height()); + // CraftBukkit start -+ double d = Painting.offsetForPaintingSize(width); -+ double d1 = Painting.offsetForPaintingSize(height); ++ double horizontalOffset = Painting.offsetForPaintingSize(width); ++ double verticalOffset = Painting.offsetForPaintingSize(height); + // CraftBukkit end - Direction counterClockWise = direction.getCounterClockWise(); - Vec3 vec31 = vec3.relative(counterClockWise, d).relative(Direction.UP, d1); + Direction left = direction.getCounterClockWise(); + Vec3 position = attachedToWall.relative(left, horizontalOffset).relative(Direction.UP, verticalOffset); Direction.Axis axis = direction.getAxis(); -- double d2 = axis == Direction.Axis.X ? 0.0625 : paintingVariant.width(); -- double d3 = paintingVariant.height(); -- double d4 = axis == Direction.Axis.Z ? 0.0625 : paintingVariant.width(); +- double xSize = axis == Direction.Axis.X ? 0.0625 : variant.width(); +- double ySize = variant.height(); +- double zSize = axis == Direction.Axis.Z ? 0.0625 : variant.width(); + // CraftBukkit start -+ double d2 = axis == Direction.Axis.X ? 0.0625 : width; -+ double d3 = height; -+ double d4 = axis == Direction.Axis.Z ? 0.0625 : width; ++ double xSize = axis == Direction.Axis.X ? 0.0625 : width; ++ double ySize = height; ++ double zSize = axis == Direction.Axis.Z ? 0.0625 : width; + // CraftBukkit end - return AABB.ofSize(vec31, d2, d3, d4); + return AABB.ofSize(position, xSize, ySize, zSize); } -- private double offsetForPaintingSize(int size) { -+ private static double offsetForPaintingSize(int size) { // CraftBukkit - static +- private double offsetForPaintingSize(final int size) { ++ private static double offsetForPaintingSize(final int size) { // CraftBukkit - static return size % 2 == 0 ? 0.5 : 0.0; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch index 8c6c4c685462..90e39c2f53d1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch @@ -6,16 +6,16 @@ protected static final EntityDataAccessor DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS); + public boolean autoExpire = true; // Paper - Expand FallingBlock API - public FallingBlockEntity(EntityType type, Level level) { + public FallingBlockEntity(final EntityType type, final Level level) { super(type, level); @@ -96,6 +_,7 @@ pos.getZ() + 0.5, state.hasProperty(BlockStateProperties.WATERLOGGED) ? state.setValue(BlockStateProperties.WATERLOGGED, false) : state ); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(fallingBlockEntity, pos, state.getFluidState().createLegacyBlock())) return fallingBlockEntity; // CraftBukkit ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) return entity; // CraftBukkit level.setBlock(pos, state.getFluidState().createLegacyBlock(), Block.UPDATE_ALL); - level.addFreshEntity(fallingBlockEntity); - return fallingBlockEntity; + level.addFreshEntity(entity); + return entity; @@ -146,13 +_,22 @@ @Override public void tick() { @@ -39,13 +39,13 @@ + // Paper end - Configurable falling blocks height nerf this.handlePortal(); if (this.level() instanceof ServerLevel serverLevel && (this.isAlive() || this.forceTickAfterTeleportToDuplicate)) { - BlockPos blockPos = this.blockPosition(); + BlockPos pos = this.blockPosition(); @@ -173,12 +_,12 @@ } - if (!this.onGround() && !flag1) { -- if (this.time > 100 && (blockPos.getY() <= this.level().getMinY() || blockPos.getY() > this.level().getMaxY()) || this.time > 600) { -+ if ((this.time > 100 && autoExpire) && (blockPos.getY() <= this.level().getMinY() || blockPos.getY() > this.level().getMaxY()) || (this.time > 600 && autoExpire)) { // Paper - Expand FallingBlock API + if (!this.onGround() && !isStuckInWater) { +- if (this.time > 100 && (pos.getY() <= this.level().getMinY() || pos.getY() > this.level().getMaxY()) || this.time > 600) { ++ if ((this.time > 100 && this.autoExpire) && (pos.getY() <= this.level().getMinY() || pos.getY() > this.level().getMaxY()) || (this.time > 600 && this.autoExpire)) { // Paper - Expand FallingBlock API if (this.dropItem && serverLevel.getGameRules().get(GameRules.ENTITY_DROPS)) { this.spawnAtLocation(serverLevel, block); } @@ -54,50 +54,50 @@ + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause } } else { - BlockState blockState = this.level().getBlockState(blockPos); -@@ -196,11 +_,17 @@ + BlockState currentState = this.level().getBlockState(pos); +@@ -195,11 +_,17 @@ this.blockState = this.blockState.setValue(BlockStateProperties.WATERLOGGED, true); } + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, this.blockState)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, this.blockState)) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // SPIGOT-6586 called before the event in previous versions + return; + } + // CraftBukkit end - if (this.level().setBlock(blockPos, this.blockState, Block.UPDATE_ALL)) { + if (this.level().setBlock(pos, this.blockState, Block.UPDATE_ALL)) { serverLevel.getChunkSource() .chunkMap - .sendToTrackingPlayers(this, new ClientboundBlockUpdatePacket(blockPos, this.level().getBlockState(blockPos))); + .sendToTrackingPlayers(this, new ClientboundBlockUpdatePacket(pos, this.level().getBlockState(pos))); - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause if (block instanceof Fallable fallable) { - fallable.onLand(this.level(), blockPos, this.blockState, blockState, this); + fallable.onLand(this.level(), pos, this.blockState, currentState, this); } -@@ -225,19 +_,19 @@ +@@ -224,19 +_,19 @@ } } } else if (this.dropItem && serverLevel.getGameRules().get(GameRules.ENTITY_DROPS)) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause - this.callOnBrokenAfterFall(block, blockPos); + this.callOnBrokenAfterFall(block, pos); this.spawnAtLocation(serverLevel, block); } } else { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause if (this.dropItem && serverLevel.getGameRules().get(GameRules.ENTITY_DROPS)) { - this.callOnBrokenAfterFall(block, blockPos); + this.callOnBrokenAfterFall(block, pos); this.spawnAtLocation(serverLevel, block); } } } else { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - this.callOnBrokenAfterFall(block, blockPos); + this.callOnBrokenAfterFall(block, pos); } } -@@ -297,6 +_,7 @@ +@@ -296,6 +_,7 @@ } output.putBoolean("CancelDrop", this.cancelDrop); @@ -105,7 +105,7 @@ } @Override -@@ -308,8 +_,9 @@ +@@ -307,8 +_,9 @@ this.fallDamagePerDistance = input.getFloatOr("FallHurtAmount", 0.0F); this.fallDamageMax = input.getIntOr("FallHurtMax", 40); this.dropItem = input.getBooleanOr("DropItem", true); @@ -115,13 +115,13 @@ + this.autoExpire = input.getBooleanOr("Paper.AutoExpire", true); // Paper - Expand FallingBlock API } - public void setHurtsEntities(float fallDamagePerDistance, int fallDamageMax) { -@@ -365,7 +_,7 @@ - ResourceKey resourceKey1 = this.level().dimension(); - boolean flag = (resourceKey1 == Level.END || resourceKey == Level.END) && resourceKey1 != resourceKey; - Entity entity = super.teleport(teleportTransition); -- this.forceTickAfterTeleportToDuplicate = entity != null && flag; -+ this.forceTickAfterTeleportToDuplicate = entity != null && flag && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation; // Paper - return entity; + public void setHurtsEntities(final float damagePerDistance, final int damageMax) { +@@ -364,7 +_,7 @@ + ResourceKey oldDimension = this.level().dimension(); + boolean fromOrToEnd = (oldDimension == Level.END || newDimension == Level.END) && oldDimension != newDimension; + Entity newEntity = super.teleport(transition); +- this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd; ++ this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation; // Paper + return newEntity; } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch index 4fda90eca2b9..0ef8416a98e3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch @@ -8,24 +8,10 @@ + private int despawnRate = -1; // Paper - Alternative item-despawn-rate + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API - public ItemEntity(EntityType type, Level level) { + public ItemEntity(final EntityType type, final Level level) { super(type, level); -@@ -58,7 +_,12 @@ - } - - public ItemEntity(Level level, double posX, double posY, double posZ, ItemStack stack) { -- this(level, posX, posY, posZ, stack, level.random.nextDouble() * 0.2 - 0.1, 0.2, level.random.nextDouble() * 0.2 - 0.1); -+ // Paper start - Don't use level random in entity constructors (to make them thread-safe) -+ this(EntityType.ITEM, level); -+ this.setPos(posX, posY, posZ); -+ this.setDeltaMovement(this.random.nextDouble() * 0.2 - 0.1, 0.2, this.random.nextDouble() * 0.2 - 0.1); -+ this.setItem(stack); -+ // Paper end - Don't use level random in entity constructors - } - - public ItemEntity(Level level, double posX, double posY, double posZ, ItemStack stack, double deltaX, double deltaY, double deltaZ) { -@@ -68,6 +_,14 @@ - this.setItem(stack); +@@ -80,6 +_,14 @@ + this.setDeltaMovement(deltaX, deltaY, deltaZ); } + // Paper start - Require item entities to send their location precisely (Fixes MC-4) @@ -39,7 +25,7 @@ @Override public boolean dampensVibrations() { return this.getItem().is(ItemTags.DAMPENS_VIBRATIONS); -@@ -104,7 +_,7 @@ +@@ -116,7 +_,7 @@ @Override public void tick() { if (this.getItem().isEmpty()) { @@ -48,25 +34,27 @@ } else { super.tick(); if (this.pickupDelay > 0 && this.pickupDelay != 32767) { -@@ -132,11 +_,15 @@ +@@ -144,13 +_,17 @@ } } -- if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-5F || (this.tickCount + this.getId()) % 4 == 0) { -+ if (!this.onGround() || this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-5F || (this.tickCount + this.getId()) % 4 == 0) { // Paper - Diff on change; ActivationRange immunity +- if (this.onGround() && !(this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-5F) && (this.tickCount + this.getId()) % 4 != 0) { ++ if (this.onGround() && !(this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-5F) && (this.tickCount + this.getId()) % 4 != 0) { // Paper - Diff on change; ActivationRange immunity + this.applyEffectsFromBlocksForLastMovements(); + } else { this.move(MoverType.SELF, this.getDeltaMovement()); this.applyEffectsFromBlocks(); - float f = 0.98F; + float friction = 0.98F; - if (this.onGround()) { + // Paper start - Friction API + if (this.frictionState == net.kyori.adventure.util.TriState.FALSE) { -+ f = 1F; ++ friction = 1F; + } else if (this.onGround()) { + // Paper end - Friction API - f = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getFriction() * 0.98F; + friction = this.level().getBlockState(this.getBlockPosBelowThatAffectsMyMovement()).getBlock().getFriction() * 0.98F; } -@@ -169,8 +_,14 @@ +@@ -183,8 +_,14 @@ } } @@ -83,27 +71,27 @@ } } } -@@ -195,9 +_,18 @@ +@@ -209,9 +_,18 @@ private void mergeWithNeighbours() { if (this.isMergable()) { + double radius = this.level().spigotConfig.itemMerge; // Spigot - for (ItemEntity itemEntity : this.level() -- .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.5, 0.0, 0.5), neighbour -> neighbour != this && neighbour.isMergable())) { -+ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D, radius), neighbour -> neighbour != this && neighbour.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally - if (itemEntity.isMergable()) { + for (ItemEntity entity : this.level() +- .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.5, 0.0, 0.5), other -> other != this && other.isMergable())) { ++ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D, radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally + if (entity.isMergable()) { + // Paper start - Fix items merging through walls + if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) { -+ if (this.level().clipDirect(this.position(), itemEntity.position(), ++ if (this.level().clipDirect(this.position(), entity.position(), + net.minecraft.world.phys.shapes.CollisionContext.of(this)) == net.minecraft.world.phys.HitResult.Type.BLOCK) { + continue; + } + } + // Paper end - Fix items merging through walls - this.tryToMerge(itemEntity); + this.tryToMerge(entity); if (this.isRemoved()) { break; -@@ -209,7 +_,7 @@ +@@ -223,7 +_,7 @@ private boolean isMergable() { ItemStack item = this.getItem(); @@ -111,37 +99,37 @@ + return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < item.getMaxStackSize(); // Paper - Alternative item-despawn-rate } - private void tryToMerge(ItemEntity itemEntity) { -@@ -242,11 +_,16 @@ + private void tryToMerge(final ItemEntity other) { +@@ -256,11 +_,16 @@ } - private static void merge(ItemEntity destinationEntity, ItemStack destinationStack, ItemEntity originEntity, ItemStack originStack) { + private static void merge(final ItemEntity toItem, final ItemStack toStack, final ItemEntity fromItem, final ItemStack fromStack) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callItemMergeEvent(originEntity, destinationEntity)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callItemMergeEvent(fromItem, toItem)) { + return; + } + // CraftBukkit end - merge(destinationEntity, destinationStack, originStack); - destinationEntity.pickupDelay = Math.max(destinationEntity.pickupDelay, originEntity.pickupDelay); - destinationEntity.age = Math.min(destinationEntity.age, originEntity.age); - if (originStack.isEmpty()) { -- originEntity.discard(); -+ originEntity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause + merge(toItem, toStack, fromStack); + toItem.pickupDelay = Math.max(toItem.pickupDelay, fromItem.pickupDelay); + toItem.age = Math.min(toItem.age, fromItem.age); + if (fromStack.isEmpty()) { +- fromItem.discard(); ++ fromItem.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause } } -@@ -274,12 +_,17 @@ - } else if (!this.getItem().canBeHurtBy(damageSource)) { +@@ -288,12 +_,17 @@ + } else if (!this.getItem().canBeHurtBy(source)) { return false; } else { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage)) { + return false; + } + // CraftBukkit end this.markHurt(); - this.health = (int)(this.health - amount); - this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); + this.health = (int)(this.health - damage); + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); if (this.health <= 0) { this.getItem().onDestroyed(this); - this.discard(); @@ -149,7 +137,7 @@ } return true; -@@ -301,6 +_,11 @@ +@@ -315,6 +_,11 @@ if (!this.getItem().isEmpty()) { output.store("Item", ItemStack.CODEC, this.getItem()); } @@ -161,7 +149,7 @@ } @Override -@@ -311,8 +_,17 @@ +@@ -325,8 +_,17 @@ this.target = input.read("Owner", UUIDUtil.CODEC).orElse(null); this.thrower = EntityReference.read(input, "Thrower"); this.setItem(input.read("Item", ItemStack.CODEC).orElse(ItemStack.EMPTY)); @@ -180,24 +168,24 @@ } } -@@ -322,10 +_,73 @@ - ItemStack item = this.getItem(); - Item item1 = item.getItem(); - int count = item.getCount(); +@@ -336,10 +_,73 @@ + ItemStack itemStack = this.getItem(); + Item item = itemStack.getItem(); + int orgCount = itemStack.getCount(); + // CraftBukkit start - fire PlayerPickupItemEvent -+ int canHold = entity.getInventory().canHold(item); -+ int remaining = count - canHold; ++ int canHold = player.getInventory().canHold(itemStack); ++ int remaining = orgCount - canHold; + boolean flyAtPlayer = false; // Paper + + // Paper start - PlayerAttemptPickupItemEvent + if (this.pickupDelay <= 0) { -+ org.bukkit.event.player.PlayerAttemptPickupItemEvent attemptEvent = new org.bukkit.event.player.PlayerAttemptPickupItemEvent((org.bukkit.entity.Player) entity.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ org.bukkit.event.player.PlayerAttemptPickupItemEvent attemptEvent = new org.bukkit.event.player.PlayerAttemptPickupItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); + this.level().getCraftServer().getPluginManager().callEvent(attemptEvent); + + flyAtPlayer = attemptEvent.getFlyAtPlayer(); + if (attemptEvent.isCancelled()) { + if (flyAtPlayer) { -+ entity.take(this, count); ++ player.take(this, orgCount); + } + + return; @@ -205,37 +193,37 @@ + } + + if (this.pickupDelay <= 0 && canHold > 0) { -+ item.setCount(canHold); ++ itemStack.setCount(canHold); + // Call legacy event -+ org.bukkit.event.player.PlayerPickupItemEvent playerEvent = new org.bukkit.event.player.PlayerPickupItemEvent((org.bukkit.entity.Player) entity.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ org.bukkit.event.player.PlayerPickupItemEvent playerEvent = new org.bukkit.event.player.PlayerPickupItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); + playerEvent.setCancelled(!playerEvent.getPlayer().getCanPickupItems()); + this.level().getCraftServer().getPluginManager().callEvent(playerEvent); + flyAtPlayer = playerEvent.getFlyAtPlayer(); // Paper + if (playerEvent.isCancelled()) { -+ item.setCount(count); // SPIGOT-5294 - restore count ++ itemStack.setCount(orgCount); // SPIGOT-5294 - restore count + // Paper start + if (flyAtPlayer) { -+ entity.take(this, count); ++ player.take(this, orgCount); + } + // Paper end + return; + } + + // Call newer event afterwards -+ org.bukkit.event.entity.EntityPickupItemEvent entityEvent = new org.bukkit.event.entity.EntityPickupItemEvent(entity.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ org.bukkit.event.entity.EntityPickupItemEvent entityEvent = new org.bukkit.event.entity.EntityPickupItemEvent(player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); + entityEvent.setCancelled(!entityEvent.getEntity().getCanPickupItems()); + this.level().getCraftServer().getPluginManager().callEvent(entityEvent); + if (entityEvent.isCancelled()) { -+ item.setCount(count); // SPIGOT-5294 - restore count ++ itemStack.setCount(orgCount); // SPIGOT-5294 - restore count + return; + } + + // Update the ItemStack if it was changed in the event + ItemStack current = this.getItem(); -+ if (!item.equals(current)) { -+ item = current; ++ if (!itemStack.equals(current)) { ++ itemStack = current; + } else { -+ item.setCount(canHold + remaining); // = i ++ itemStack.setCount(canHold + remaining); // = i + } + + // Possibly < 0; fix here so we do not have to modify code below @@ -246,24 +234,24 @@ + } + // CraftBukkit end + // Paper end - PlayerAttemptPickupItemEvent - if (this.pickupDelay == 0 && (this.target == null || this.target.equals(entity.getUUID())) && entity.getInventory().add(item)) { + if (this.pickupDelay == 0 && (this.target == null || this.target.equals(player.getUUID())) && player.getInventory().add(itemStack)) { + if (flyAtPlayer) // Paper - PlayerPickupItemEvent - entity.take(this, count); - if (item.isEmpty()) { + player.take(this, orgCount); + if (itemStack.isEmpty()) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - item.setCount(count); + itemStack.setCount(orgCount); } -@@ -362,6 +_,7 @@ +@@ -376,6 +_,7 @@ - public void setItem(ItemStack stack) { - this.getEntityData().set(DATA_ITEM, stack); -+ this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate + public void setItem(final ItemStack itemStack) { + this.getEntityData().set(DATA_ITEM, itemStack); ++ this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(itemStack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate } - @Override -@@ -414,7 +_,7 @@ + public void setTarget(final @Nullable UUID target) { +@@ -420,7 +_,7 @@ public void makeFakeItem() { this.setNeverPickUp(); @@ -271,4 +259,4 @@ + this.age = this.despawnRate - 1; // Spigot // Paper - Alternative item-despawn-rate } - public static float getSpin(float age, float bobOffset) { + public static float getSpin(final float ageInTicks, final float bobOffset) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch index 2c49055d3d3f..ed22259d6bcd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch @@ -13,24 +13,24 @@ public class PrimedTnt extends Entity implements TraceableEntity { private static final EntityDataAccessor DATA_FUSE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.INT); private static final EntityDataAccessor DATA_BLOCK_STATE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.BLOCK_STATE); -@@ -51,6 +_,7 @@ +@@ -53,6 +_,7 @@ public @Nullable EntityReference owner; private boolean usedPortal; public float explosionPower = 4.0F; + public boolean isIncendiary = false; // CraftBukkit - public PrimedTnt(EntityType type, Level level) { + public PrimedTnt(final EntityType type, final Level level) { super(type, level); -@@ -60,7 +_,7 @@ - public PrimedTnt(Level level, double x, double y, double z, @Nullable LivingEntity owner) { +@@ -62,7 +_,7 @@ + public PrimedTnt(final Level level, final double x, final double y, final double z, final @Nullable LivingEntity owner) { this(EntityType.TNT, level); this.setPos(x, y, z); -- double d = level.random.nextDouble() * (float) (Math.PI * 2); -+ double d = this.random.nextDouble() * (float) (Math.PI * 2); // Paper - Don't use level random in entity constructors - this.setDeltaMovement(-Math.sin(d) * 0.02, 0.2F, -Math.cos(d) * 0.02); +- double rot = level.getRandom().nextDouble() * (float) (Math.PI * 2); ++ double rot = this.getRandom().nextDouble() * (float) (Math.PI * 2); // Paper - Don't use level random in entity constructors + this.setDeltaMovement(-Math.sin(rot) * 0.02, 0.2F, -Math.cos(rot) * 0.02); this.setFuse(80); this.xo = x; -@@ -92,10 +_,17 @@ +@@ -94,10 +_,17 @@ @Override public void tick() { @@ -48,10 +48,10 @@ this.setDeltaMovement(this.getDeltaMovement().scale(0.98)); if (this.onGround()) { this.setDeltaMovement(this.getDeltaMovement().multiply(0.7, -0.5, 0.7)); -@@ -104,20 +_,35 @@ - int i = this.getFuse() - 1; - this.setFuse(i); - if (i <= 0) { +@@ -106,20 +_,35 @@ + int fuse = this.getFuse() - 1; + this.setFuse(fuse); + if (fuse <= 0) { - this.discard(); + // CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event + //this.discard(); @@ -61,7 +61,7 @@ + this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause + // CraftBukkit end } else { - this.updateInWaterStateAndDoFluidPushing(); + this.updateFluidInteraction(); if (this.level().isClientSide()) { this.level().addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5, this.getZ(), 0.0, 0.0, 0.0); } @@ -75,7 +75,7 @@ } private void explode() { - if (this.level() instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.TNT_EXPLODES)) { + if (this.level() instanceof ServerLevel level && level.getGameRules().get(GameRules.TNT_EXPLODES)) { + // CraftBukkit start + ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); + if (event.isCancelled()) { @@ -85,7 +85,7 @@ this.level() .explode( this, -@@ -126,8 +_,8 @@ +@@ -128,8 +_,8 @@ this.getX(), this.getY(0.0625), this.getZ(), @@ -96,8 +96,8 @@ Level.ExplosionInteraction.TNT ); } -@@ -199,4 +_,11 @@ - public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { +@@ -201,4 +_,11 @@ + public final boolean hurtServer(final ServerLevel level, final DamageSource source, final float damage) { return false; } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch index 65fc6a540624..7f4bb9c08612 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch @@ -6,7 +6,7 @@ public boolean droppedSkulls; + public @Nullable Entity entityIgniter; // CraftBukkit - public Creeper(EntityType type, Level level) { + public Creeper(final EntityType type, final Level level) { super(type, level); @@ -118,7 +_,7 @@ this.maxSwell = input.getShortOr("Fuse", (short)30); @@ -21,8 +21,8 @@ } @Override -- public void setTarget(@Nullable LivingEntity target) { -+ public boolean setTarget(@Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit +- public void setTarget(final @Nullable LivingEntity target) { ++ public boolean setTarget(final @Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit if (!(target instanceof Goat)) { - super.setTarget(target); + return super.setTarget(target, reason); // CraftBukkit @@ -33,10 +33,10 @@ @Override @@ -203,9 +_,20 @@ @Override - public void thunderHit(ServerLevel level, LightningBolt lightning) { - super.thunderHit(level, lightning); + public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { + super.thunderHit(level, lightningBolt); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callCreeperPowerEvent(this, lightning, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callCreeperPowerEvent(this, lightningBolt, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { + return; + } + // CraftBukkit end @@ -50,32 +50,32 @@ + // CraftBukkit end + @Override - protected InteractionResult mobInteract(Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + protected InteractionResult mobInteract(final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); @@ -214,8 +_,9 @@ this.level() .playSound(player, this.getX(), this.getY(), this.getZ(), soundEvent, this.getSoundSource(), 1.0F, this.random.nextFloat() * 0.4F + 0.8F); if (!this.level().isClientSide()) { + this.entityIgniter = player; // CraftBukkit this.ignite(); -- if (!itemInHand.isDamageableItem()) { -+ if (itemInHand.getMaxDamage() == 0) { // CraftBukkit - fix MC-264285: unbreakable flint and steels are completely consumed when igniting a creeper - itemInHand.shrink(1); +- if (!itemStack.isDamageableItem()) { ++ if (itemStack.getMaxDamage() == 0) { // CraftBukkit - fix MC-264285: unbreakable flint and steels are completely consumed when igniting a creeper + itemStack.shrink(1); } else { - itemInHand.hurtAndBreak(1, player, hand.asEquipmentSlot()); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); @@ -231,18 +_,29 @@ public void explodeCreeper() { - if (this.level() instanceof ServerLevel serverLevel) { - float f = this.isPowered() ? 2.0F : 1.0F; + if (this.level() instanceof ServerLevel level) { + float explosionMultiplier = this.isPowered() ? 2.0F : 1.0F; + // CraftBukkit start -+ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); ++ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * explosionMultiplier, false); + if (!event.isCancelled()) { + // CraftBukkit end this.dead = true; -- serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), this.explosionRadius * f, Level.ExplosionInteraction.MOB); -+ serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) +- level.explode(this, this.getX(), this.getY(), this.getZ(), this.explosionRadius * explosionMultiplier, Level.ExplosionInteraction.MOB); ++ level.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) this.spawnLingeringCloud(); - this.triggerOnDeathMobEffects(serverLevel, Entity.RemovalReason.KILLED); + this.triggerOnDeathMobEffects(level, Entity.RemovalReason.KILLED); - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause + // CraftBukkit start @@ -91,19 +91,19 @@ Collection activeEffects = this.getActiveEffects(); - if (!activeEffects.isEmpty()) { + if (!activeEffects.isEmpty() && !this.level().paperConfig().entities.behavior.disableCreeperLingeringEffect) { // Paper - Option to disable creeper lingering effect - AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); -+ areaEffectCloud.setOwner(this); // CraftBukkit - areaEffectCloud.setRadius(2.5F); - areaEffectCloud.setRadiusOnUse(-0.5F); - areaEffectCloud.setWaitTime(10); + AreaEffectCloud cloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); ++ cloud.setOwner(this); // CraftBukkit + cloud.setRadius(2.5F); + cloud.setRadiusOnUse(-0.5F); + cloud.setWaitTime(10); @@ -254,15 +_,26 @@ - areaEffectCloud.addEffect(new MobEffectInstance(mobEffectInstance)); + cloud.addEffect(new MobEffectInstance(mobEffect)); } -- this.level().addFreshEntity(areaEffectCloud); +- this.level().addFreshEntity(cloud); - } - } -+ this.level().addFreshEntity(areaEffectCloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // CraftBukkit ++ this.level().addFreshEntity(cloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // CraftBukkit + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch index c3d2fb4778d2..08823a50a2b6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch @@ -3,9 +3,9 @@ @@ -65,7 +_,7 @@ super.customServerAiStep(level); if ((this.tickCount + this.getId()) % 1200 == 0) { - MobEffectInstance mobEffectInstance = new MobEffectInstance(MobEffects.MINING_FATIGUE, 6000, 2); -- List list = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, mobEffectInstance, 1200); -+ List list = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, mobEffectInstance, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, (player) -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian) this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent - list.forEach( - serverPlayer -> serverPlayer.connection + MobEffectInstance miningFatigue = new MobEffectInstance(MobEffects.MINING_FATIGUE, 6000, 2); +- List affectedPlayers = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, miningFatigue, 1200); ++ List affectedPlayers = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, miningFatigue, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, player -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian)this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent + affectedPlayers.forEach( + player -> player.connection .send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch index a7435e6abc0d..2e6fd539b7c9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch @@ -11,7 +11,7 @@ + // Paper end - EndermanEscapeEvent + @Override -- public void setTarget(@Nullable LivingEntity target) { +- public void setTarget(final @Nullable LivingEntity target) { - super.setTarget(target); + // CraftBukkit start - fire event + public boolean setTarget(@Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { @@ -20,11 +20,11 @@ + } + target = this.getTarget(); + // CraftBukkit end - AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); + AttributeInstance movementSpeed = this.getAttribute(Attributes.MOVEMENT_SPEED); if (target == null) { this.targetChangeTime = 0; @@ -135,6 +_,7 @@ - attribute.addTransientModifier(SPEED_MODIFIER_ATTACKING); + movementSpeed.addTransientModifier(SPEED_MODIFIER_ATTACKING); } } + return true; // CraftBukkit @@ -34,7 +34,7 @@ @@ -207,6 +_,15 @@ } - boolean isBeingStaredBy(Player player) { + private boolean isBeingStaredBy(final Player player) { + // Paper start - EndermanAttackPlayerEvent + final boolean shouldAttack = this.isBeingStaredBy0(player); + final com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity()); @@ -47,31 +47,31 @@ return LivingEntity.PLAYER_NOT_WEARING_DISGUISE_ITEM.test(player) && this.isLookingAtMe(player, 0.025, true, false, this.getEyeY()); } -@@ -246,7 +_,7 @@ - float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); - if (lightLevelDependentMagicValue > 0.5F - && level.canSeeSky(this.blockPosition()) -- && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F) { -+ && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent +@@ -244,7 +_,7 @@ + protected void customServerAiStep(final ServerLevel level) { + if (level.isBrightOutside() && this.tickCount >= this.targetChangeTime + 600) { + float br = this.getLightLevelDependentMagicValue(); +- if (br > 0.5F && level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (br - 0.4F) * 2.0F) { ++ if (br > 0.5F && level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (br - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent this.setTarget(null); this.teleport(); } -@@ -358,21 +_,25 @@ - AbstractThrownPotion abstractThrownPotion1 = damageSource.getDirectEntity() instanceof AbstractThrownPotion abstractThrownPotion - ? abstractThrownPotion - : null; -- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && abstractThrownPotion1 == null) { -+ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && abstractThrownPotion1 == null) { // Paper - EndermanEscapeEvent - diff on change - below logic relies on this path covering non-projectile damage. - boolean flag = super.hurtServer(level, damageSource, amount); - if (!(damageSource.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) { -+ if (this.tryEscape(damageSource.is(net.minecraft.tags.DamageTypeTags.IS_DROWNING) ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper - EndermanEscapeEvent +@@ -354,21 +_,25 @@ + return false; + } else { + AbstractThrownPotion thrownPotion = source.getDirectEntity() instanceof AbstractThrownPotion potion ? potion : null; +- if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { ++ if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { // Paper - EndermanEscapeEvent - diff on change - below logic relies on this path covering non-projectile damage. + boolean result = super.hurtServer(level, source, damage); + if (!(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) { ++ if (this.tryEscape(source.is(net.minecraft.tags.DamageTypeTags.IS_DROWNING) ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper - EndermanEscapeEvent this.teleport(); + } // Paper - EndermanEscapeEvent } - return flag; + return result; } else { - boolean flag = abstractThrownPotion1 != null && this.hurtWithCleanWater(level, damageSource, abstractThrownPotion1, amount); + boolean hurtWithCleanWater = thrownPotion != null && this.hurtWithCleanWater(level, source, thrownPotion, damage); + if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent for (int i = 0; i < 64; i++) { @@ -81,9 +81,9 @@ } + } // Paper - EndermanEscapeEvent - return flag; + return hurtWithCleanWater; } -@@ -397,6 +_,16 @@ +@@ -393,6 +_,16 @@ this.entityData.set(DATA_STARED_AT, true); } @@ -100,28 +100,28 @@ @Override public boolean requiresCustomPersistence() { return super.requiresCustomPersistence() || this.getCarriedBlock() != null; -@@ -455,16 +_,19 @@ - int floor1 = Mth.floor(this.enderman.getY() + random.nextDouble() * 2.0); - int floor2 = Mth.floor(this.enderman.getZ() - 1.0 + random.nextDouble() * 2.0); - BlockPos blockPos = new BlockPos(floor, floor1, floor2); -- BlockState blockState = level.getBlockState(blockPos); -+ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent endermen from loading chunks -+ if (blockState == null) return; // Paper - Prevent endermen from loading chunks - BlockPos blockPos1 = blockPos.below(); - BlockState blockState1 = level.getBlockState(blockPos1); - BlockState carriedBlock = this.enderman.getCarriedBlock(); - if (carriedBlock != null) { - carriedBlock = Block.updateFromNeighbourShapes(carriedBlock, this.enderman.level(), blockPos); - if (this.canPlaceBlock(level, blockPos, carriedBlock, blockState, blockState1, blockPos1)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockPos, carriedBlock)) { // CraftBukkit - Place event - level.setBlock(blockPos, carriedBlock, Block.UPDATE_ALL); - level.gameEvent(GameEvent.BLOCK_PLACE, blockPos, GameEvent.Context.of(this.enderman, carriedBlock)); +@@ -451,16 +_,19 @@ + int yt = Mth.floor(this.enderman.getY() + random.nextDouble() * 2.0); + int zt = Mth.floor(this.enderman.getZ() - 1.0 + random.nextDouble() * 2.0); + BlockPos pos = new BlockPos(xt, yt, zt); +- BlockState targetState = level.getBlockState(pos); ++ BlockState targetState = level.getBlockStateIfLoaded(pos); // Paper - Prevent endermen from loading chunks ++ if (targetState == null) return; // Paper - Prevent endermen from loading chunks + BlockPos below = pos.below(); + BlockState belowState = level.getBlockState(below); + BlockState carried = this.enderman.getCarriedBlock(); + if (carried != null) { + carried = Block.updateFromNeighbourShapes(carried, this.enderman.level(), pos); + if (this.canPlaceBlock(level, pos, carried, targetState, belowState, below)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, pos, carried)) { // CraftBukkit - Place event + level.setBlock(pos, carried, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(this.enderman, carried)); this.enderman.setCarriedBlock(null); + } // CraftBukkit } } } -@@ -561,7 +_,7 @@ +@@ -552,7 +_,7 @@ } else { if (this.target != null && !this.enderman.isPassenger()) { if (this.enderman.isBeingStaredBy((Player)this.target)) { @@ -130,21 +130,21 @@ this.enderman.teleport(); } -@@ -600,15 +_,18 @@ - int floor1 = Mth.floor(this.enderman.getY() + random.nextDouble() * 3.0); - int floor2 = Mth.floor(this.enderman.getZ() - 2.0 + random.nextDouble() * 4.0); - BlockPos blockPos = new BlockPos(floor, floor1, floor2); -- BlockState blockState = level.getBlockState(blockPos); -+ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent endermen from loading chunks +@@ -591,15 +_,18 @@ + int yt = Mth.floor(this.enderman.getY() + random.nextDouble() * 3.0); + int zt = Mth.floor(this.enderman.getZ() - 2.0 + random.nextDouble() * 4.0); + BlockPos pos = new BlockPos(xt, yt, zt); +- BlockState blockState = level.getBlockState(pos); ++ BlockState blockState = level.getBlockStateIfLoaded(pos); // Paper - Prevent endermen from loading chunks + if (blockState == null) return; // Paper - Prevent endermen from loading chunks - Vec3 vec3 = new Vec3(this.enderman.getBlockX() + 0.5, floor1 + 0.5, this.enderman.getBlockZ() + 0.5); - Vec3 vec31 = new Vec3(floor + 0.5, floor1 + 0.5, floor2 + 0.5); - BlockHitResult blockHitResult = level.clip(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman)); - boolean flag = blockHitResult.getBlockPos().equals(blockPos); - if (blockState.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockPos, blockState.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state - level.removeBlock(blockPos, false); - level.gameEvent(GameEvent.BLOCK_DESTROY, blockPos, GameEvent.Context.of(this.enderman, blockState)); + Vec3 from = new Vec3(this.enderman.getBlockX() + 0.5, yt + 0.5, this.enderman.getBlockZ() + 0.5); + Vec3 to = new Vec3(xt + 0.5, yt + 0.5, zt + 0.5); + BlockHitResult result = level.clip(new ClipContext(from, to, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman)); + boolean reachable = result.getBlockPos().equals(pos); + if (blockState.is(BlockTags.ENDERMAN_HOLDABLE) && reachable) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, pos, blockState.getFluidState().createLegacyBlock())) { // Paper - Place event + level.removeBlock(pos, false); + level.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(this.enderman, blockState)); this.enderman.setCarriedBlock(blockState.getBlock().defaultBlockState()); + } // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch index 39e04cd088fe..831086353ed5 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch @@ -10,14 +10,14 @@ + } + // Paper end + - private static boolean isReflectedFireball(DamageSource damageSource) { - return damageSource.getDirectEntity() instanceof LargeFireball && damageSource.getEntity() instanceof Player; + private static boolean isReflectedFireball(final DamageSource source) { + return source.getDirectEntity() instanceof LargeFireball && source.getEntity() instanceof Player; } -@@ -368,6 +_,7 @@ +@@ -375,6 +_,7 @@ } - LargeFireball largeFireball = new LargeFireball(level, this.ghast, vec3.normalize(), this.ghast.getExplosionPower()); -+ largeFireball.bukkitYield = largeFireball.explosionPower = this.ghast.getExplosionPower(); // CraftBukkit - set bukkitYield when setting explosionPower - largeFireball.setPos(this.ghast.getX() + viewVector.x * 4.0, this.ghast.getY(0.5) + 0.5, largeFireball.getZ() + viewVector.z * 4.0); - level.addFreshEntity(largeFireball); + LargeFireball entity = new LargeFireball(level, this.ghast, direction.normalize(), this.ghast.getExplosionPower()); ++ entity.bukkitYield = entity.explosionPower = this.ghast.getExplosionPower(); // CraftBukkit - set bukkitYield when setting explosionPower + entity.setPos(this.ghast.getX() + viewVector.x * 4.0, this.ghast.getY(0.5) + 0.5, entity.getZ() + viewVector.z * 4.0); + level.addFreshEntity(entity); this.chargeTime = -40; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch index e15e6f685444..70b864f1a433 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch @@ -6,14 +6,14 @@ public @Nullable RandomStrollGoal randomStrollGoal; + public Guardian.GuardianAttackGoal guardianAttackGoal; // CraftBukkit - add field - public Guardian(EntityType type, Level level) { + public Guardian(final EntityType type, final Level level) { super(type, level); @@ -72,7 +_,7 @@ protected void registerGoals() { - MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0); + MoveTowardsRestrictionGoal goal = new MoveTowardsRestrictionGoal(this, 1.0); this.randomStrollGoal = new RandomStrollGoal(this, 1.0, 80); - this.goalSelector.addGoal(4, new Guardian.GuardianAttackGoal(this)); + this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field - this.goalSelector.addGoal(5, moveTowardsRestrictionGoal); + this.goalSelector.addGoal(5, goal); this.goalSelector.addGoal(7, this.randomStrollGoal); this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch index 2e5c2131d42e..2e282f76bf20 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch @@ -4,8 +4,8 @@ return false; } else { DimensionType dimensionType = level.dimensionType(); -- int i = dimensionType.monsterSpawnBlockLightLimit(); -+ int i = level.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning - if (i < 15 && level.getBrightness(LightLayer.BLOCK, pos) > i) { +- int blockLightLimit = dimensionType.monsterSpawnBlockLightLimit(); ++ int blockLightLimit = level.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning + if (blockLightLimit < 15 && level.getBrightness(LightLayer.BLOCK, pos) > blockLightLimit) { return false; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch index 65f2c4e2f0cf..26878838bcfa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/entity/monster/Phantom.java +++ b/net/minecraft/world/entity/monster/Phantom.java -@@ -49,6 +_,10 @@ - Vec3 moveTargetPoint = Vec3.ZERO; - @Nullable public BlockPos anchorPoint; - Phantom.AttackPhase attackPhase = Phantom.AttackPhase.CIRCLE; +@@ -50,6 +_,10 @@ + private Vec3 moveTargetPoint = Vec3.ZERO; + public @Nullable BlockPos anchorPoint; + private Phantom.AttackPhase attackPhase = Phantom.AttackPhase.CIRCLE; + // Paper start + public java.util.@Nullable UUID spawningEntity; + public boolean shouldBurnInDay = true; + // Paper end - public Phantom(EntityType type, Level level) { + public Phantom(final EntityType type, final Level level) { super(type, level); -@@ -136,6 +_,13 @@ +@@ -137,6 +_,13 @@ } } @@ -23,9 +23,9 @@ + // Paper end + @Override - protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { + protected void checkFallDamage(final double ya, final boolean onGround, final BlockState onState, final BlockPos pos) { } -@@ -164,6 +_,10 @@ +@@ -165,6 +_,10 @@ super.readAdditionalSaveData(input); this.anchorPoint = input.read("anchor_pos", BlockPos.CODEC).orElse(null); this.setPhantomSize(input.getIntOr("size", 0)); @@ -36,7 +36,7 @@ } @Override -@@ -171,6 +_,10 @@ +@@ -172,6 +_,10 @@ super.addAdditionalSaveData(output); output.storeNullable("anchor_pos", BlockPos.CODEC, this.anchorPoint); output.putInt("size", this.getPhantomSize()); @@ -47,10 +47,10 @@ } @Override -@@ -244,8 +_,10 @@ +@@ -240,8 +_,10 @@ - for (Player player : nearbyPlayers) { - if (Phantom.this.canAttack(serverLevel, player, TargetingConditions.DEFAULT)) { + for (Player player : players) { + if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) { - Phantom.this.setTarget(player); + if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls + Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch index a0e52436cfed..9b646732659e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch @@ -1,31 +1,31 @@ --- a/net/minecraft/world/entity/monster/Ravager.java +++ b/net/minecraft/world/entity/monster/Ravager.java -@@ -155,12 +_,19 @@ - BlockState blockState = serverLevel.getBlockState(blockPos); - Block block = blockState.getBlock(); +@@ -153,12 +_,19 @@ + BlockState state = serverLevel.getBlockState(pos); + Block block = state.getBlock(); if (block instanceof LeavesBlock) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end - flag = serverLevel.destroyBlock(blockPos, true, this) || flag; + destroyedBlock = serverLevel.destroyBlock(pos, true, this) || destroyedBlock; } } - if (!flag && this.onGround()) { + if (!destroyedBlock && this.onGround()) { + if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API this.jumpFromGround(); + } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop } } -@@ -250,7 +_,7 @@ - double d = entity.getX() - this.getX(); - double d1 = entity.getZ() - this.getZ(); - double max = Math.max(d * d + d1 * d1, 0.001); -- entity.push(d / max * 4.0, 0.2, d1 / max * 4.0); -+ entity.push(d / max * 4.0, 0.2, d1 / max * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent +@@ -249,7 +_,7 @@ + double xd = entity.getX() - this.getX(); + double zd = entity.getZ() - this.getZ(); + double dd = Math.max(xd * xd + zd * zd, 0.001); +- entity.push(xd / dd * 4.0, 0.2, zd / dd * 4.0); ++ entity.push(xd / dd * 4.0, 0.2, zd / dd * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch index a709e8da5f32..bf6f4acfc070 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Shulker.java +++ b/net/minecraft/world/entity/monster/Shulker.java -@@ -276,8 +_,10 @@ +@@ -277,8 +_,10 @@ } @Override @@ -13,32 +13,32 @@ if (this.level().isClientSide()) { this.clientOldAttachPosition = this.blockPosition(); } -@@ -388,6 +_,14 @@ - && this.level().getWorldBorder().isWithinBounds(blockPos1) - && this.level().noCollision(this, new AABB(blockPos1).deflate(1.0E-6))) { - Direction direction = this.findAttachableSurface(blockPos1); +@@ -389,6 +_,14 @@ + && this.level().getWorldBorder().isWithinBounds(target) + && this.level().noCollision(this, new AABB(target).deflate(1.0E-6))) { + Direction attachmentDirection = this.findAttachableSurface(target); + // CraftBukkit start -+ org.bukkit.event.entity.EntityTeleportEvent teleportEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, blockPos1.getX(), blockPos1.getY(), blockPos1.getZ()); ++ org.bukkit.event.entity.EntityTeleportEvent teleportEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, target.getX(), target.getY(), target.getZ()); + if (teleportEvent.isCancelled() || teleportEvent.getTo() == null) { // Paper + return false; + } else { -+ blockPos1 = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(teleportEvent.getTo()); ++ target = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(teleportEvent.getTo()); + } + // CraftBukkit end - if (direction != null) { + if (attachmentDirection != null) { this.unRide(); - this.setAttachFace(direction); -@@ -452,7 +_,12 @@ - if (shulker != null) { - shulker.setVariant(this.getVariant()); - shulker.snapTo(vec3); -- this.level().addFreshEntity(shulker); + this.setAttachFace(attachmentDirection); +@@ -453,7 +_,12 @@ + if (baby != null) { + baby.setVariant(this.getVariant()); + baby.snapTo(oldPosition); +- this.level().addFreshEntity(baby); + // Paper start - Call ShulkerDuplicateEvent -+ if (!new io.papermc.paper.event.entity.ShulkerDuplicateEvent((org.bukkit.entity.Shulker) shulker.getBukkitEntity(), (org.bukkit.entity.Shulker) this.getBukkitEntity()).callEvent()) { ++ if (!new io.papermc.paper.event.entity.ShulkerDuplicateEvent((org.bukkit.entity.Shulker) baby.getBukkitEntity(), (org.bukkit.entity.Shulker) this.getBukkitEntity()).callEvent()) { + return; + } + // Paper end - Call ShulkerDuplicateEvent -+ this.level().addFreshEntity(shulker, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - the mysteries of life ++ this.level().addFreshEntity(baby, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - the mysteries of life } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch index d764f077a1cb..0bf09e3dd85b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch @@ -10,15 +10,15 @@ } } @@ -168,9 +_,14 @@ - BlockPos blockPos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection); - BlockState blockState = levelAccessor.getBlockState(blockPos); + BlockPos pos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection); + BlockState blockState = level.getBlockState(pos); if (InfestedBlock.isCompatibleHostBlock(blockState)) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, InfestedBlock.infestedStateByHost(blockState))) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, pos, InfestedBlock.infestedStateByHost(blockState))) { + return; + } + // CraftBukkit end - levelAccessor.setBlock(blockPos, InfestedBlock.infestedStateByHost(blockState), Block.UPDATE_ALL); + level.setBlock(pos, InfestedBlock.infestedStateByHost(blockState), Block.UPDATE_ALL); this.mob.spawnAnim(); - this.mob.discard(); + this.mob.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause @@ -26,15 +26,15 @@ } } @@ -210,6 +_,12 @@ - BlockState blockState = level.getBlockState(blockPos1); + BlockState blockState = level.getBlockState(testPos); Block block = blockState.getBlock(); if (block instanceof InfestedBlock) { + // CraftBukkit start -+ BlockState afterState = getServerLevel(level).getGameRules().get(GameRules.MOB_GRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockPos1, afterState)) { // Paper - fix wrong block state ++ BlockState afterState = getServerLevel(level).getGameRules().get(GameRules.MOB_GRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(testPos)); // Paper - fix wrong block state ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, testPos, afterState)) { // Paper - fix wrong block state + continue; + } + // CraftBukkit end if (getServerLevel(level).getGameRules().get(GameRules.MOB_GRIEFING)) { - level.destroyBlock(blockPos1, true, this.silverfish); + level.destroyBlock(testPos, true, this.silverfish); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch index 9ed5f13b01f3..5bcb18c5999e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch @@ -6,7 +6,7 @@ private boolean wasOnGround = false; + private boolean canWander = true; // Paper - Slime pathfinder events - public Slime(EntityType type, Level level) { + public Slime(final EntityType type, final Level level) { super(type, level); @@ -113,6 +_,7 @@ super.addAdditionalSaveData(output); @@ -28,34 +28,34 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause int size = this.getSize(); if (!this.level().isClientSide() && size > 1 && this.isDeadOrDying()) { float width = this.getDimensions(this.getPose()).width(); @@ -202,18 +_,43 @@ - int i = size / 2; - int i1 = 2 + this.random.nextInt(3); + int halfSize = size / 2; + int count = 2 + this.random.nextInt(3); PlayerTeam team = this.getTeam(); + // CraftBukkit start -+ org.bukkit.event.entity.SlimeSplitEvent event = new org.bukkit.event.entity.SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), i1); ++ org.bukkit.event.entity.SlimeSplitEvent event = new org.bukkit.event.entity.SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), count); + if (event.callEvent() && event.getCount() > 0) { -+ i1 = event.getCount(); ++ count = event.getCount(); + } else { + super.remove(reason, eventCause); // CraftBukkit - add Bukkit remove cause + return; + } + -+ java.util.List slimes = new java.util.ArrayList<>(i1); ++ java.util.List slimes = new java.util.ArrayList<>(count); + // CraftBukkit end - for (int i2 = 0; i2 < i1; i2++) { - float f1 = (i2 % 2 - 0.5F) * f; - float f2 = (i2 / 2 - 0.5F) * f; -- this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, mob -> { -+ Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, (mob) -> { // CraftBukkit - mob.setSize(i, true); - mob.snapTo(this.getX() + f1, this.getY() + 0.5, this.getZ() + f2, this.random.nextFloat() * 360.0F, 0.0F); + for (int i = 0; i < count; i++) { + float xd = (i % 2 - 0.5F) * xzSlimeSpawnOffset; + float zd = (i / 2 - 0.5F) * xzSlimeSpawnOffset; +- this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, slime -> { ++ Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, slime -> { // CraftBukkit + slime.setSize(halfSize, true); + slime.snapTo(this.getX() + xd, this.getY() + 0.5, this.getZ() + zd, this.random.nextFloat() * 360.0F, 0.0F); - }); - } + // CraftBukkit start @@ -81,8 +81,8 @@ } @Override -@@ -279,7 +_,11 @@ - return checkMobSpawnRules(entityType, level, spawnReason, pos, random); +@@ -276,7 +_,11 @@ + return checkMobSpawnRules(type, level, spawnReason, pos, random); } - if (level.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70) { @@ -91,24 +91,24 @@ + final double minHeightSwamp = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum; + // Paper end - Replace rules for Height in Swamp Biomes + if (level.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp) { // Paper - Replace rules for Height in Swamp Biomes - float value = level.environmentAttributes().getValue(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE, pos); - if (random.nextFloat() < value && level.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { - return checkMobSpawnRules(entityType, level, spawnReason, pos, random); -@@ -291,8 +_,11 @@ + float surfaceSlimeSpawnChance = level.environmentAttributes().getValue(EnvironmentAttributes.SURFACE_SLIME_SPAWN_CHANCE, pos); + if (random.nextFloat() < surfaceSlimeSpawnChance && level.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { + return checkMobSpawnRules(type, level, spawnReason, pos, random); +@@ -288,8 +_,11 @@ } - ChunkPos chunkPos = new ChunkPos(pos); -- boolean flag = WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel)level).getSeed(), 987234911L).nextInt(10) == 0; -- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { -+ boolean flag = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Paper + ChunkPos chunkPos = ChunkPos.containing(pos); +- boolean slimeChunk = WorldgenRandom.seedSlimeChunk(chunkPos.x(), chunkPos.z(), ((WorldGenLevel)level).getSeed(), 987234911L).nextInt(10) == 0; +- if (random.nextInt(10) == 0 && slimeChunk && pos.getY() < 40) { ++ boolean slimeChunk = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkPos.x(), chunkPos.z(), ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Paper + // Paper start - Replace rules for Height in Slime Chunks + final double maxHeightSlimeChunk = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; -+ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { ++ if (random.nextInt(10) == 0 && slimeChunk && pos.getY() < maxHeightSlimeChunk) { + // Paper end - Replace rules for Height in Slime Chunks - return checkMobSpawnRules(entityType, level, spawnReason, pos, random); + return checkMobSpawnRules(type, level, spawnReason, pos, random); } } -@@ -350,6 +_,16 @@ +@@ -347,6 +_,16 @@ return super.getDefaultDimensions(pose).scale(this.getSize()); } @@ -122,10 +122,10 @@ + } + // Paper end - Slime pathfinder events + - static class SlimeAttackGoal extends Goal { + private static class SlimeAttackGoal extends Goal { private final Slime slime; private int growTiredTimer; -@@ -362,7 +_,16 @@ +@@ -359,7 +_,16 @@ @Override public boolean canUse() { LivingEntity target = this.slime.getTarget(); @@ -143,7 +143,7 @@ } @Override -@@ -374,7 +_,16 @@ +@@ -371,7 +_,16 @@ @Override public boolean canContinueToUse() { LivingEntity target = this.slime.getTarget(); @@ -161,7 +161,7 @@ } @Override -@@ -393,6 +_,13 @@ +@@ -390,6 +_,13 @@ slimeMoveControl.setDirection(this.slime.getYRot(), this.slime.isDealsDamage()); } } @@ -174,8 +174,8 @@ + // Paper end - Slime pathfinder events } - static class SlimeFloatGoal extends Goal { -@@ -406,7 +_,7 @@ + private static class SlimeFloatGoal extends Goal { +@@ -403,7 +_,7 @@ @Override public boolean canUse() { @@ -184,7 +184,7 @@ } @Override -@@ -436,7 +_,7 @@ +@@ -433,7 +_,7 @@ @Override public boolean canUse() { @@ -193,7 +193,7 @@ } @Override -@@ -514,7 +_,7 @@ +@@ -511,7 +_,7 @@ @Override public boolean canUse() { @@ -202,7 +202,7 @@ && (this.slime.onGround() || this.slime.isInWater() || this.slime.isInLava() || this.slime.hasEffect(MobEffects.LEVITATION)) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; } -@@ -524,6 +_,11 @@ +@@ -521,6 +_,11 @@ if (--this.nextRandomizeTime <= 0) { this.nextRandomizeTime = this.adjustedTickDelay(40 + this.slime.getRandom().nextInt(60)); this.chosenDegrees = this.slime.getRandom().nextInt(360); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch index 7da583c2e8c5..1293ab1271f9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java -@@ -294,7 +_,14 @@ - || blockStateOnLegacy.is(BlockTags.STRIDER_WARM_BLOCKS) +@@ -299,7 +_,14 @@ + || stateOn.is(BlockTags.STRIDER_WARM_BLOCKS) || this.getFluidHeight(FluidTags.LAVA) > 0.0; - boolean flag1 = this.getVehicle() instanceof Strider strider && strider.isSuffocating(); -- this.setSuffocating(!flag || flag1); + boolean onWarmStrider = this.getVehicle() instanceof Strider strider && !strider.isSuffocating(); +- this.setSuffocating(!inWarmBlocks && !onWarmStrider); + // CraftBukkit start -+ boolean suffocating = !flag || flag1; ++ boolean suffocating = !inWarmBlocks && !onWarmStrider; + if (suffocating ^ this.isSuffocating()) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callStriderTemperatureChangeEvent(this, suffocating)) { + this.setSuffocating(suffocating); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch index 2c78ad8e6565..aa33a3442320 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Vex.java +++ b/net/minecraft/world/entity/monster/Vex.java -@@ -288,7 +_,7 @@ +@@ -293,7 +_,7 @@ @Override public void start() { Mob owner = Vex.this.getOwner(); @@ -9,15 +9,15 @@ super.start(); } } -@@ -347,7 +_,10 @@ +@@ -355,7 +_,10 @@ - for (int i = 0; i < 3; i++) { - BlockPos blockPos = boundOrigin.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); -- if (Vex.this.level().isEmptyBlock(blockPos)) { + for (int attempts = 0; attempts < 3; attempts++) { + BlockPos testPos = boundOrigin.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); +- if (Vex.this.level().isEmptyBlock(testPos)) { + // Paper start - Don't load chunks -+ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockPos); ++ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(testPos); + if (blockState != null && blockState.isAir()) { + // Paper end - Don't load chunks - Vex.this.moveControl.setWantedPosition(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5, 0.25); + Vex.this.moveControl.setWantedPosition(testPos.getX() + 0.5, testPos.getY() + 0.5, testPos.getZ() + 0.5, 0.25); if (Vex.this.getTarget() == null) { - Vex.this.getLookControl().setLookAt(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5, 180.0F, 20.0F); + Vex.this.getLookControl().setLookAt(testPos.getX() + 0.5, testPos.getY() + 0.5, testPos.getZ() + 0.5, 180.0F, 20.0F); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch index a0ab0a12072c..ba743428ffc4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch @@ -1,26 +1,26 @@ --- a/net/minecraft/world/entity/monster/Witch.java +++ b/net/minecraft/world/entity/monster/Witch.java @@ -123,8 +_,14 @@ - ItemStack mainHandItem = this.getMainHandItem(); + ItemStack itemStack = this.getMainHandItem(); this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); - PotionContents potionContents = mainHandItem.get(DataComponents.POTION_CONTENTS); + PotionContents potion = itemStack.get(DataComponents.POTION_CONTENTS); + // Paper start - WitchConsumePotionEvent -+ if (mainHandItem.is(Items.POTION)) { -+ com.destroystokyo.paper.event.entity.WitchConsumePotionEvent event = new com.destroystokyo.paper.event.entity.WitchConsumePotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(mainHandItem)); -+ potionContents = event.callEvent() ? org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getPotion()).get(DataComponents.POTION_CONTENTS) : null; ++ if (itemStack.is(Items.POTION)) { ++ com.destroystokyo.paper.event.entity.WitchConsumePotionEvent event = new com.destroystokyo.paper.event.entity.WitchConsumePotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack)); ++ potion = event.callEvent() ? org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getPotion()).get(DataComponents.POTION_CONTENTS) : null; + } + // Paper end - WitchConsumePotionEvent - if (mainHandItem.is(Items.POTION) && potionContents != null) { -- potionContents.forEachEffect(this::addEffect, mainHandItem.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F)); -+ potionContents.forEachEffect(effect -> this.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK), mainHandItem.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F)); // CraftBukkit + if (itemStack.is(Items.POTION) && potion != null) { +- potion.forEachEffect(this::addEffect, itemStack.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F)); ++ potion.forEachEffect(effect -> this.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK), itemStack.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F)); // CraftBukkit } this.gameEvent(GameEvent.DRINK); @@ -148,26 +_,7 @@ } - if (holder != null) { -- this.setItemSlot(EquipmentSlot.MAINHAND, PotionContents.createItemStack(Items.POTION, holder)); + if (potion != null) { +- this.setItemSlot(EquipmentSlot.MAINHAND, PotionContents.createItemStack(Items.POTION, potion)); - this.usingTime = this.getMainHandItem().getUseDuration(this); - this.setUsingItem(true); - if (!this.isSilent()) { @@ -37,10 +37,10 @@ - ); - } - -- AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); -- attribute.removeModifier(SPEED_MODIFIER_DRINKING_ID); -- attribute.addTransientModifier(SPEED_MODIFIER_DRINKING); -+ this.setDrinkingPotion(PotionContents.createItemStack(Items.POTION, holder)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out +- AttributeInstance speed = this.getAttribute(Attributes.MOVEMENT_SPEED); +- speed.removeModifier(SPEED_MODIFIER_DRINKING_ID); +- speed.addTransientModifier(SPEED_MODIFIER_DRINKING); ++ this.setDrinkingPotion(PotionContents.createItemStack(Items.POTION, potion)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out } } @@ -58,10 +58,10 @@ + this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F); + } + -+ AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); ++ AttributeInstance speed = this.getAttribute(Attributes.MOVEMENT_SPEED); + -+ attribute.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID); -+ attribute.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING); ++ speed.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID); ++ speed.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING); + } + // Paper end + @@ -71,7 +71,7 @@ @@ -245,6 +_,13 @@ if (this.level() instanceof ServerLevel serverLevel) { - ItemStack itemStack = PotionContents.createItemStack(Items.SPLASH_POTION, holder); + ItemStack itemStack = PotionContents.createItemStack(Items.SPLASH_POTION, potion); + // Paper start - WitchThrowPotionEvent + com.destroystokyo.paper.event.entity.WitchThrowPotionEvent event = new com.destroystokyo.paper.event.entity.WitchThrowPotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), (org.bukkit.entity.LivingEntity) target.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack)); + if (!event.callEvent()) { @@ -79,6 +79,6 @@ + } + itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion()); + // Paper end - WitchThrowPotionEven - Projectile.spawnProjectileUsingShoot(ThrownSplashPotion::new, serverLevel, itemStack, this, d, d1 + squareRoot * 0.2, d2, 0.75F, 8.0F); - } - + Projectile.spawnProjectileUsingShoot( + ThrownSplashPotion::new, serverLevel, itemStack, this, xd, yd + dist * 0.2, zd, dist <= 2.0 ? 0.45F : 0.75F, 8.0F + ); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch index c6c994ce5369..0cbe4ba51bf8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch @@ -1,10 +1,14 @@ --- a/net/minecraft/world/entity/monster/breeze/Breeze.java +++ b/net/minecraft/world/entity/monster/breeze/Breeze.java -@@ -245,6 +_,7 @@ +@@ -242,6 +_,11 @@ @Override - public boolean canAttackType(EntityType type) { -+ if (this.getTarget() != null) return this.getTarget().getType() == type; // SPIGOT-7957: Allow attack if target from brain was set - return type == EntityType.PLAYER || type == EntityType.IRON_GOLEM; + public boolean canAttack(final LivingEntity target) { ++ // TODO - snapshot - reimplement but without reintroducing MC-199589 ++ // CraftBukkit start - SPIGOT-7957: Allow attack if target from brain was set ++ // LivingEntity targetFromBrain = this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); ++ // if (targetFromBrain != null) return target.is(targetFromBrain); ++ // CraftBukkit end + return (target.is(EntityType.PLAYER) || target.is(EntityType.IRON_GOLEM)) && super.canAttack(target); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch index cebc12470b3a..e1f7aa867c05 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/entity/monster/creaking/Creaking.java +++ b/net/minecraft/world/entity/monster/creaking/Creaking.java -@@ -192,9 +_,9 @@ +@@ -191,9 +_,9 @@ } @Override -- public void push(double x, double y, double z) { -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param +- public void push(final double xa, final double ya, final double za) { ++ public void push(final double xa, final double ya, final double za, @Nullable final Entity pushingEntity) { // Paper - add push source entity param if (this.canMove()) { -- super.push(x, y, z); -+ super.push(x, y, z, pushingEntity); // Paper - add push source entity param +- super.push(xa, ya, za); ++ super.push(xa, ya, za, pushingEntity); // Paper - add push source entity param } } -@@ -319,7 +_,7 @@ +@@ -318,7 +_,7 @@ } this.makeSound(this.getDeathSound()); @@ -20,16 +20,16 @@ + this.remove(Entity.RemovalReason.DISCARDED, null); // CraftBukkit - add Bukkit remove cause } - public void creakingDeathEffects(DamageSource damageSource) { -@@ -447,9 +_,9 @@ + public void creakingDeathEffects(final DamageSource source) { +@@ -446,9 +_,9 @@ } @Override -- public void knockback(double strength, double x, double z) { -+ public void knockback(double strength, double x, double z, @Nullable Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause) { // Paper - knockback events +- public void knockback(final double power, final double xd, final double zd) { ++ public void knockback(final double power, final double xd, final double zd, @Nullable final Entity attacker, final io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause) { // Paper - knockback events if (this.canMove()) { -- super.knockback(strength, x, z); -+ super.knockback(strength, x, z, attacker, cause); // Paper - knockback events +- super.knockback(power, xd, zd); ++ super.knockback(power, xd, zd, attacker, cause); // Paper - knockback events } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch index 3d2981564dac..690df3a34440 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/Hoglin.java.patch @@ -1,11 +1,13 @@ --- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -266,7 +_,12 @@ +@@ -237,9 +_,12 @@ } private void finishConversion() { -- this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), mob -> mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0))); -+ final Entity converted = this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), mob -> {mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons +- this.convertTo( +- EntityType.ZOGLIN, ConversionParams.single(this, true, false), zoglin -> zoglin.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0)) +- ); ++ final Entity converted = this.convertTo(EntityType.ZOGLIN, ConversionParams.single(this, true, false), zoglin -> {zoglin.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons + // Paper start - Fix issues with mob conversion; reset to prevent event spam + if (converted == null) { + this.timeInOverworld = 0; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/HoglinBase.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/HoglinBase.java.patch index 273ab55a4d24..52948f5cd93f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/HoglinBase.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/hoglin/HoglinBase.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/hoglin/HoglinBase.java +++ b/net/minecraft/world/entity/monster/hoglin/HoglinBase.java -@@ -45,7 +_,7 @@ - double d3 = d * (hoglin.level().random.nextFloat() * 0.5F + 0.2F); - Vec3 vec3 = new Vec3(d1, 0.0, d2).normalize().scale(d3).yRot(f); - double d4 = d * hoglin.level().random.nextFloat() * 0.5; -- target.push(vec3.x, d4, vec3.z); -+ target.push(vec3.x, d4, vec3.z, hoglin); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent +@@ -47,7 +_,7 @@ + double horizontalScale = effectiveKnockbackPower * (random.nextFloat() * 0.5F + 0.2F); + Vec3 horizontalPushVector = new Vec3(xd, 0.0, zd).normalize().scale(horizontalScale).yRot(horizontalPushAngle); + double verticalScale = effectiveKnockbackPower * random.nextFloat() * 0.5; +- target.push(horizontalPushVector.x, verticalScale, horizontalPushVector.z); ++ target.push(horizontalPushVector.x, verticalScale, horizontalPushVector.z, body); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent target.hurtMarked = true; } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch index 1c8641669946..48f194a1f2da 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/illager/Evoker.java +++ b/net/minecraft/world/entity/monster/illager/Evoker.java -@@ -247,7 +_,7 @@ - serverLevel.getScoreboard().addPlayerToTeam(vex.getScoreboardName(), team); +@@ -271,7 +_,7 @@ + serverLevel.getScoreboard().addPlayerToTeam(vex.getScoreboardName(), evokerTeam); } - serverLevel.addFreshEntityWithPassengers(vex); + serverLevel.addFreshEntityWithPassengers(vex, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPELL); // CraftBukkit - Add SpawnReason - serverLevel.gameEvent(GameEvent.ENTITY_PLACE, blockPos, GameEvent.Context.of(Evoker.this)); + serverLevel.gameEvent(GameEvent.ENTITY_PLACE, pos, GameEvent.Context.of(Evoker.this)); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch index 07a12f5fd228..9be002440e38 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch @@ -1,39 +1,39 @@ --- a/net/minecraft/world/entity/monster/illager/Illusioner.java +++ b/net/minecraft/world/entity/monster/illager/Illusioner.java -@@ -174,7 +_,8 @@ +@@ -175,7 +_,8 @@ @Override - public void performRangedAttack(LivingEntity target, float distanceFactor) { -- ItemStack itemInHand = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW)); + public void performRangedAttack(final LivingEntity target, final float power) { +- ItemStack bowItem = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW)); + net.minecraft.world.InteractionHand hand = ProjectileUtil.getWeaponHoldingHand(this, Items.BOW); // Paper - call EntityShootBowEvent -+ ItemStack itemInHand = this.getItemInHand(hand); // Paper - call EntityShootBowEvent - ItemStack projectile = this.getProjectile(itemInHand); - AbstractArrow mobArrow = ProjectileUtil.getMobArrow(this, projectile, distanceFactor, itemInHand); - double d = target.getX() - this.getX(); -@@ -182,9 +_,21 @@ - double d2 = target.getZ() - this.getZ(); - double squareRoot = Math.sqrt(d * d + d2 * d2); ++ ItemStack bowItem = this.getItemInHand(hand); // Paper - call EntityShootBowEvent + ItemStack projectile = this.getProjectile(bowItem); + AbstractArrow arrow = ProjectileUtil.getMobArrow(this, projectile, power, bowItem); + double xd = target.getX() - this.getX(); +@@ -183,9 +_,21 @@ + double zd = target.getZ() - this.getZ(); + double distanceToTarget = Math.sqrt(xd * xd + zd * zd); if (this.level() instanceof ServerLevel serverLevel) { - Projectile.spawnProjectileUsingShoot( + Projectile.Delayed delayedEntity = Projectile.spawnProjectileUsingShootDelayed( // Paper - delayed - mobArrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 + arrow, serverLevel, projectile, xd, yd + distanceToTarget * 0.2F, zd, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 ); + + // Paper start - call EntityShootBowEvent -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, itemInHand, mobArrow.getPickupItem(), mobArrow, hand, distanceFactor, true); ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, bowItem, arrow.getPickupItem(), arrow, hand, power, true); + if (event.isCancelled()) { + event.getProjectile().remove(); + return; + } + -+ if (event.getProjectile() == mobArrow.getBukkitEntity()) { ++ if (event.getProjectile() == arrow.getBukkitEntity()) { + delayedEntity.spawn(); + } + // Paper end - call EntityShootBowEvent } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -231,7 +_,7 @@ +@@ -237,7 +_,7 @@ @Override protected void performSpellCasting() { @@ -42,7 +42,7 @@ } @Override -@@ -263,7 +_,7 @@ +@@ -274,7 +_,7 @@ @Override protected void performSpellCasting() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Pillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Pillager.java.patch index 575d644e7872..cce9a641bcac 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Pillager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Pillager.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/entity/monster/illager/Pillager.java @@ -215,7 +_,7 @@ this.onItemPickup(entity); - ItemStack itemStack = this.inventory.addItem(item); - if (itemStack.isEmpty()) { + ItemStack remainder = this.inventory.addItem(itemStack); + if (remainder.isEmpty()) { - entity.discard(); + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { - item.setCount(itemStack.getCount()); + itemStack.setCount(remainder.getCount()); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch index 5eaaf1fba832..3c1ea820e027 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java +++ b/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java -@@ -210,6 +_,11 @@ +@@ -216,6 +_,11 @@ public void tick() { this.attackWarmupDelay--; if (this.attackWarmupDelay == 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch index 9e3dfa15dd41..a88a50bae4af 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Vindicator.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/monster/illager/Vindicator.java +++ b/net/minecraft/world/entity/monster/illager/Vindicator.java -@@ -183,7 +_,7 @@ +@@ -181,7 +_,7 @@ - static class VindicatorBreakDoorGoal extends BreakDoorGoal { - public VindicatorBreakDoorGoal(Mob mob) { + private static class VindicatorBreakDoorGoal extends BreakDoorGoal { + public VindicatorBreakDoorGoal(final Mob mob) { - super(mob, 6, Vindicator.DOOR_BREAKING_PREDICATE); + super(mob, 6, com.google.common.base.Predicates.in(mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(mob.getType(), mob.level().paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.VINDICATOR)))); // Paper - Configurable door breaking difficulty this.setFlags(EnumSet.of(Goal.Flag.MOVE)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch index c8b899872eaf..f0ec4bf4ca57 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch @@ -1,13 +1,15 @@ --- a/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java +++ b/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -@@ -102,9 +_,14 @@ +@@ -102,11 +_,16 @@ } - protected void finishConversion(ServerLevel level) { + protected void finishConversion(final ServerLevel level) { - this.convertTo( -- EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0)) + net.minecraft.world.entity.Entity converted = this.convertTo( // Paper - Fix issues with mob conversion; reset to prevent event spam -+ EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> {mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED // CraftBukkit - add spawn and transform reasons + EntityType.ZOMBIFIED_PIGLIN, + ConversionParams.single(this, true, true), +- zombified -> zombified.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0)) ++ zombified -> {zombified.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED // CraftBukkit - add spawn and transform reasons ); + // Paper start - Fix issues with mob conversion; reset to prevent event spam + if (converted == null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch index 531622193478..cc9ead32c126 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -129,6 +_,12 @@ - MemoryModuleType.SPEAR_ENGAGE_TIME, - MemoryModuleType.SPEAR_STATUS +@@ -96,6 +_,12 @@ + List.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.NEAREST_ITEMS, SensorType.HURT_BY, SensorType.PIGLIN_SPECIFIC_SENSOR), + PiglinAi::getActivities ); + // CraftBukkit start - Custom bartering and interest list + public java.util.Set allowedBarterItems = new java.util.HashSet<>(); @@ -11,9 +11,9 @@ + .byNameCodec().listOf().xmap(java.util.HashSet::new, List::copyOf); + // CraftBukkit end - public Piglin(EntityType type, Level level) { + public Piglin(final EntityType type, final Level level) { super(type, level); -@@ -141,6 +_,10 @@ +@@ -108,6 +_,10 @@ output.putBoolean("IsBaby", this.isBaby()); output.putBoolean("CannotHunt", this.cannotHunt); this.writeInventoryToTag(output); @@ -24,7 +24,7 @@ } @Override -@@ -149,6 +_,10 @@ +@@ -116,6 +_,10 @@ this.setBaby(input.getBooleanOr("IsBaby", false)); this.setCannotHunt(input.getBooleanOr("CannotHunt", false)); this.readInventoryFromTag(input); @@ -35,9 +35,9 @@ } @VisibleForDebug -@@ -314,7 +_,9 @@ +@@ -282,7 +_,9 @@ @Override - protected void finishConversion(ServerLevel level) { + protected void finishConversion(final ServerLevel level) { PiglinAi.cancelAdmiring(level, this); + this.forceDrops = true; // Paper - Add missing forceDrop toggles this.inventory.removeAllItems().forEach(itemStack -> this.spawnAtLocation(level, itemStack)); @@ -45,29 +45,30 @@ super.finishConversion(level); } -@@ -391,7 +_,7 @@ +@@ -359,7 +_,7 @@ } - protected void holdInOffHand(ItemStack stack) { -- if (stack.is(PiglinAi.BARTERING_ITEM)) { -+ if (stack.is(PiglinAi.BARTERING_ITEM) || this.allowedBarterItems.contains(stack.getItem())) { // CraftBukkit - Changes to accept custom payment items - this.setItemSlot(EquipmentSlot.OFFHAND, stack); + protected void holdInOffHand(final ItemStack itemStack) { +- if (itemStack.is(PiglinAi.BARTERING_ITEM)) { ++ if (itemStack.is(PiglinAi.BARTERING_ITEM) || this.allowedBarterItems.contains(itemStack.getItem())) { // CraftBukkit - Changes to accept custom payment items + this.setItemSlot(EquipmentSlot.OFFHAND, itemStack); this.setGuaranteedDrop(EquipmentSlot.OFFHAND); } else { -@@ -416,15 +_,15 @@ +@@ -384,8 +_,8 @@ return false; } else { TagKey preferredWeaponType = this.getPreferredWeaponType(); -- boolean flag = PiglinAi.isLovedItem(newItem) || preferredWeaponType != null && newItem.is(preferredWeaponType); -- boolean flag1 = PiglinAi.isLovedItem(currentItem) || preferredWeaponType != null && currentItem.is(preferredWeaponType); -+ boolean flag = PiglinAi.isLovedItem(newItem, this) || preferredWeaponType != null && newItem.is(preferredWeaponType); // CraftBukkit -+ boolean flag1 = PiglinAi.isLovedItem(currentItem, this) || preferredWeaponType != null && currentItem.is(preferredWeaponType); // CraftBukkit - return flag && !flag1 || (flag || !flag1) && super.canReplaceCurrentItem(newItem, currentItem, slot); +- boolean newItemWanted = PiglinAi.isLovedItem(newItemStack) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); +- boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); ++ boolean newItemWanted = PiglinAi.isLovedItem(newItemStack, this) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); // CraftBukkit ++ boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack, this) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); // CraftBukkit + return newItemWanted && !currentItemWanted + || (newItemWanted || !currentItemWanted) && super.canReplaceCurrentItem(newItemStack, currentItemStack, slot); } - } +@@ -393,7 +_,7 @@ @Override - protected void pickUpItem(ServerLevel level, ItemEntity entity) { + protected void pickUpItem(final ServerLevel level, final ItemEntity entity) { - this.onItemPickup(entity); + // this.onItemPickup(entity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired PiglinAi.pickUpItem(level, this, entity); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch index d0c0a517b7e0..ae7121d1021c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch @@ -1,154 +1,143 @@ --- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java +++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -335,24 +_,26 @@ - - protected static void pickUpItem(ServerLevel level, Piglin piglin, ItemEntity itemEntity) { - stopWalking(piglin); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().is(Items.GOLD_NUGGET) ? 0 : itemEntity.getItem().getCount() - 1).isCancelled()) return; // Paper -+ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification - ItemStack item; +@@ -338,16 +_,18 @@ + protected static void pickUpItem(final ServerLevel level, final Piglin body, final ItemEntity itemEntity) { + stopWalking(body); + ItemStack taken; ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(body, itemEntity, itemEntity.getItem().is(Items.GOLD_NUGGET) ? 0 : itemEntity.getItem().getCount() - 1).isCancelled()) return; // Paper ++ body.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification if (itemEntity.getItem().is(Items.GOLD_NUGGET)) { -- piglin.take(itemEntity, itemEntity.getItem().getCount()); -+ piglin.take(itemEntity, itemEntity.getItem().getCount()); // Paper - diff on change for above event - item = itemEntity.getItem(); + body.take(itemEntity, itemEntity.getItem().getCount()); + taken = itemEntity.getItem(); - itemEntity.discard(); + itemEntity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { -- piglin.take(itemEntity, 1); -+ piglin.take(itemEntity, 1); // Paper - diff on change for above event - item = removeOneItemFromItemEntity(itemEntity); + body.take(itemEntity, 1); + taken = removeOneItemFromItemEntity(itemEntity); } -- if (isLovedItem(item)) { -+ if (isLovedItem(item, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering - piglin.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); - holdInOffhand(level, piglin, item); - admireGoldItem(piglin); - } else if (isFood(item) && !hasEatenRecently(piglin)) { - eat(piglin); - } else { -- boolean flag = !piglin.equipItemIfPossible(level, item).equals(ItemStack.EMPTY); -+ boolean flag = !piglin.equipItemIfPossible(level, item, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above. - if (!flag) { - putInInventory(piglin, item); - } -@@ -361,7 +_,9 @@ +- if (isLovedItem(taken)) { ++ if (isLovedItem(taken, body)) { // CraftBukkit - Changes to allow for custom payment in bartering + body.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); + holdInOffhand(level, body, taken); + admireGoldItem(body); +@@ -363,7 +_,9 @@ - private static void holdInOffhand(ServerLevel level, Piglin piglin, ItemStack stack) { - if (isHoldingItemInOffHand(piglin)) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(level, piglin.getItemInHand(InteractionHand.OFF_HAND)); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles + private static void holdInOffhand(final ServerLevel level, final Piglin body, final ItemStack itemStack) { + if (isHoldingItemInOffHand(body)) { ++ body.forceDrops = true; // Paper - Add missing forceDrop toggles + body.spawnAtLocation(level, body.getItemInHand(InteractionHand.OFF_HAND)); ++ body.forceDrops = false; // Paper - Add missing forceDrop toggles } - piglin.holdInOffHand(stack); -@@ -371,7 +_,7 @@ - ItemStack item = itemEntity.getItem(); - ItemStack itemStack = item.split(1); - if (item.isEmpty()) { + body.holdInOffHand(itemStack); +@@ -373,7 +_,7 @@ + ItemStack sourceStack = itemEntity.getItem(); + ItemStack removedStack = sourceStack.split(1); + if (sourceStack.isEmpty()) { - itemEntity.discard(); + itemEntity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { - itemEntity.setItem(item); + itemEntity.setItem(sourceStack); } -@@ -383,9 +_,14 @@ - ItemStack itemInHand = piglin.getItemInHand(InteractionHand.OFF_HAND); - piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); - if (piglin.isAdult()) { -- boolean isBarterCurrency = isBarterCurrency(itemInHand); -+ boolean isBarterCurrency = isBarterCurrency(itemInHand, piglin); // CraftBukkit - Changes to allow custom payment for bartering - if (barter && isBarterCurrency) { -- throwItems(piglin, getBarterResponseItems(piglin)); +@@ -385,9 +_,14 @@ + ItemStack itemStack = body.getItemInHand(InteractionHand.OFF_HAND); + body.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + if (body.isAdult()) { +- boolean barterCurrency = isBarterCurrency(itemStack); ++ boolean barterCurrency = isBarterCurrency(itemStack, body); // CraftBukkit - Changes to allow custom payment for bartering + if (barteringEnabled && barterCurrency) { +- throwItems(body, getBarterResponseItems(body)); + // CraftBukkit start -+ org.bukkit.event.entity.PiglinBarterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPiglinBarterEvent(piglin, getBarterResponseItems(piglin), itemInHand); ++ org.bukkit.event.entity.PiglinBarterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPiglinBarterEvent(body, getBarterResponseItems(body), itemStack); + if (!event.isCancelled()) { -+ throwItems(piglin, event.getOutcome().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).collect(java.util.stream.Collectors.toList())); ++ throwItems(body, event.getOutcome().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).collect(java.util.stream.Collectors.toList())); + } + // CraftBukkit end - } else if (!isBarterCurrency) { - boolean flag = !piglin.equipItemIfPossible(level, itemInHand).isEmpty(); - if (!flag) { -@@ -396,7 +_,7 @@ - boolean isBarterCurrency = !piglin.equipItemIfPossible(level, itemInHand).isEmpty(); - if (!isBarterCurrency) { - ItemStack mainHandItem = piglin.getMainHandItem(); + } else if (!barterCurrency) { + boolean equipped = !body.equipItemIfPossible(level, itemStack).isEmpty(); + if (!equipped) { +@@ -398,7 +_,7 @@ + boolean equipped = !body.equipItemIfPossible(level, itemStack).isEmpty(); + if (!equipped) { + ItemStack mainHandItem = body.getMainHandItem(); - if (isLovedItem(mainHandItem)) { -+ if (isLovedItem(mainHandItem, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering - putInInventory(piglin, mainHandItem); ++ if (isLovedItem(mainHandItem, body)) { // CraftBukkit - Changes to allow for custom payment in bartering + putInInventory(body, mainHandItem); } else { - throwItems(piglin, Collections.singletonList(mainHandItem)); -@@ -409,7 +_,9 @@ + throwItems(body, Collections.singletonList(mainHandItem)); +@@ -411,7 +_,9 @@ - protected static void cancelAdmiring(ServerLevel level, Piglin piglin) { - if (isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(level, piglin.getOffhandItem()); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles - piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + protected static void cancelAdmiring(final ServerLevel level, final Piglin body) { + if (isAdmiringItem(body) && !body.getOffhandItem().isEmpty()) { ++ body.forceDrops = true; // Paper - Add missing forceDrop toggles + body.spawnAtLocation(level, body.getOffhandItem()); ++ body.forceDrops = false; // Paper - Add missing forceDrop toggles + body.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); } } -@@ -465,7 +_,7 @@ +@@ -467,7 +_,7 @@ return false; - } else if (isAdmiringDisabled(piglin) && piglin.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { + } else if (isAdmiringDisabled(body) && body.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { return false; -- } else if (isBarterCurrency(stack)) { -+ } else if (isBarterCurrency(stack, piglin)) { // CraftBukkit - return isNotHoldingLovedItemInOffHand(piglin); +- } else if (isBarterCurrency(itemStack)) { ++ } else if (isBarterCurrency(itemStack, body)) { // CraftBukkit + return isNotHoldingLovedItemInOffHand(body); } else { - boolean canAddToInventory = piglin.canAddToInventory(stack); -@@ -474,11 +_,16 @@ - } else if (isFood(stack)) { - return !hasEatenRecently(piglin) && canAddToInventory; + boolean hasSpace = body.canAddToInventory(itemStack); +@@ -476,11 +_,16 @@ + } else if (isFood(itemStack)) { + return !hasEatenRecently(body) && hasSpace; } else { -- return !isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory; -+ return !isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory; // Paper - upstream missed isLovedItem check +- return !isLovedItem(itemStack) ? body.canReplaceCurrentItem(itemStack) : isNotHoldingLovedItemInOffHand(body) && hasSpace; ++ return !isLovedItem(itemStack, body) ? body.canReplaceCurrentItem(itemStack) : isNotHoldingLovedItemInOffHand(body) && hasSpace; // Paper - upstream missed isLovedItem check } } } + // CraftBukkit start - Added method to allow checking for custom payment items -+ protected static boolean isLovedItem(ItemStack item, Piglin piglin) { -+ return PiglinAi.isLovedItem(item) || (piglin.interestItems.contains(item.getItem()) || piglin.allowedBarterItems.contains(item.getItem())); ++ protected static boolean isLovedItem(final ItemStack itemStack, final Piglin body) { ++ return PiglinAi.isLovedItem(itemStack) || (body.interestItems.contains(itemStack.getItem()) || body.allowedBarterItems.contains(itemStack.getItem())); + } + // CraftBukkit end - protected static boolean isLovedItem(ItemStack item) { - return item.is(ItemTags.PIGLIN_LOVED); + protected static boolean isLovedItem(final ItemStack itemStack) { + return itemStack.is(ItemTags.PIGLIN_LOVED); } -@@ -530,6 +_,7 @@ +@@ -540,6 +_,7 @@ } - public static void angerNearbyPiglins(ServerLevel level, Player player, boolean requireLineOfSight) { + public static void angerNearbyPiglins(final ServerLevel level, final Player player, final boolean onlyIfTheySeeThePlayer) { + if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests - List entitiesOfClass = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0)); - entitiesOfClass.stream().filter(PiglinAi::isIdle).filter(piglin -> !requireLineOfSight || BehaviorUtils.canSee(piglin, player)).forEach(piglin -> { + List nearbyPiglins = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0)); + nearbyPiglins.stream().filter(PiglinAi::isIdle).filter(piglin -> !onlyIfTheySeeThePlayer || BehaviorUtils.canSee(piglin, player)).forEach(piglin -> { if (level.getGameRules().get(GameRules.UNIVERSAL_ANGER)) { -@@ -554,7 +_,7 @@ +@@ -564,7 +_,7 @@ } - protected static boolean canAdmire(Piglin piglin, ItemStack stack) { -- return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack); -+ return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack, piglin); // CraftBukkit + protected static boolean canAdmire(final Piglin body, final ItemStack playerHeldItemStack) { +- return !isAdmiringDisabled(body) && !isAdmiringItem(body) && body.isAdult() && isBarterCurrency(playerHeldItemStack); ++ return !isAdmiringDisabled(body) && !isAdmiringItem(body) && body.isAdult() && isBarterCurrency(playerHeldItemStack, body); // CraftBukkit } - protected static void wasHurtBy(ServerLevel level, Piglin piglin, LivingEntity entity) { -@@ -802,6 +_,11 @@ - return piglin.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); + protected static void wasHurtBy(final ServerLevel level, final Piglin body, final LivingEntity attacker) { +@@ -813,6 +_,11 @@ + return body.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); } + // CraftBukkit start - Changes to allow custom payment for bartering -+ private static boolean isBarterCurrency(ItemStack item, Piglin piglin) { -+ return PiglinAi.isBarterCurrency(item) || piglin.allowedBarterItems.contains(item.getItem()); ++ private static boolean isBarterCurrency(final ItemStack itemStack, final Piglin body) { ++ return PiglinAi.isBarterCurrency(itemStack) || body.allowedBarterItems.contains(itemStack.getItem()); + } + // CraftBukkit end - private static boolean isBarterCurrency(ItemStack stack) { - return stack.is(BARTERING_ITEM); + private static boolean isBarterCurrency(final ItemStack itemStack) { + return itemStack.is(BARTERING_ITEM); } -@@ -839,7 +_,7 @@ +@@ -850,7 +_,7 @@ } - private static boolean isNotHoldingLovedItemInOffHand(Piglin piglin) { -- return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem()); -+ return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem(), piglin); // CraftBukkit - Changes to allow custom payment for bartering + private static boolean isNotHoldingLovedItemInOffHand(final Piglin body) { +- return body.getOffhandItem().isEmpty() || !isLovedItem(body.getOffhandItem()); ++ return body.getOffhandItem().isEmpty() || !isLovedItem(body.getOffhandItem(), body); // CraftBukkit - Changes to allow custom payment for bartering } - public static boolean isZombified(EntityType entityType) { + public static boolean isZombified(final Entity entity) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch index 108bb28ad52d..0f515a9b2f00 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java +++ b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java -@@ -66,6 +_,7 @@ +@@ -71,6 +_,7 @@ AbstractSkeleton.this.setAggressive(true); } }; + private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API - protected AbstractSkeleton(EntityType type, Level level) { + protected AbstractSkeleton(final EntityType type, final Level level) { super(type, level); -@@ -90,6 +_,21 @@ +@@ -95,6 +_,21 @@ return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.25); } @@ -28,9 +28,9 @@ + // Paper end - shouldBurnInDay API + @Override - protected void playStepSound(BlockPos pos, BlockState block) { + protected void playStepSound(final BlockPos pos, final BlockState blockState) { this.playSound(this.getStepSound(), 0.15F, 1.0F); -@@ -120,7 +_,7 @@ +@@ -125,7 +_,7 @@ this.populateDefaultEquipmentSlots(random, difficulty); this.populateDefaultEquipmentEnchantments(level, random, difficulty); this.reassessWeaponGoal(); @@ -39,27 +39,27 @@ if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && SpecialDates.isHalloween() && random.nextFloat() < 0.25F) { this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); this.setDropChance(EquipmentSlot.HEAD, 0.0F); -@@ -158,7 +_,8 @@ +@@ -163,7 +_,8 @@ @Override - public void performRangedAttack(LivingEntity target, float distanceFactor) { -- ItemStack itemInHand = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW)); + public void performRangedAttack(final LivingEntity target, final float power) { +- ItemStack bowItem = this.getItemInHand(ProjectileUtil.getWeaponHoldingHand(this, Items.BOW)); + net.minecraft.world.InteractionHand hand = ProjectileUtil.getWeaponHoldingHand(this, Items.BOW); // Paper - call EntityShootBowEvent -+ ItemStack itemInHand = this.getItemInHand(hand); // Paper - call EntityShootBowEvent - ItemStack projectile = this.getProjectile(itemInHand); - AbstractArrow arrow = this.getArrow(projectile, distanceFactor, itemInHand); - double d = target.getX() - this.getX(); -@@ -166,9 +_,21 @@ - double d2 = target.getZ() - this.getZ(); - double squareRoot = Math.sqrt(d * d + d2 * d2); ++ ItemStack bowItem = this.getItemInHand(hand); // Paper - call EntityShootBowEvent + ItemStack projectile = this.getProjectile(bowItem); + AbstractArrow arrow = this.getArrow(projectile, power, bowItem); + double xd = target.getX() - this.getX(); +@@ -171,9 +_,21 @@ + double zd = target.getZ() - this.getZ(); + double distanceToTarget = Math.sqrt(xd * xd + zd * zd); if (this.level() instanceof ServerLevel serverLevel) { - Projectile.spawnProjectileUsingShoot( + Projectile.Delayed delayedEntity = Projectile.spawnProjectileUsingShootDelayed( // Paper - delayed - arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 + arrow, serverLevel, projectile, xd, yd + distanceToTarget * 0.2F, zd, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 ); + + // Paper start - call EntityShootBowEvent -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, itemInHand, arrow.getPickupItem(), arrow, hand, distanceFactor, true); ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, bowItem, arrow.getPickupItem(), arrow, hand, power, true); + if (event.isCancelled()) { + event.getProjectile().remove(); + return; @@ -72,17 +72,27 @@ } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -192,11 +_,22 @@ - protected void readAdditionalSaveData(ValueInput input) { +@@ -197,11 +_,14 @@ + protected void readAdditionalSaveData(final ValueInput input) { super.readAdditionalSaveData(input); this.reassessWeaponGoal(); -- } -- -- @Override -- public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem) { -- super.onEquipItem(slot, oldItem, newItem); + this.shouldBurnInDay = input.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - shouldBurnInDay API -+ } + } + ++ // Paper start - silent equipping + @Override +- public void onEquipItem(final EquipmentSlot slot, final ItemStack oldStack, final ItemStack stack) { +- super.onEquipItem(slot, oldStack, stack); ++ public void onEquipItem(final EquipmentSlot slot, final ItemStack oldStack, final ItemStack stack, boolean silent) { ++ super.onEquipItem(slot, oldStack, stack, silent); ++ // Paper end - silent equipping + if (!this.level().isClientSide()) { + this.reassessWeaponGoal(); + } +@@ -215,4 +_,12 @@ + public boolean wantsToPickUp(final ServerLevel level, final ItemStack itemStack) { + return !itemStack.is(ItemTags.SPEARS) && super.wantsToPickUp(level, itemStack); + } + + // Paper start - shouldBurnInDay API + @Override @@ -91,12 +101,4 @@ + output.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); + } + // Paper end - shouldBurnInDay API -+ -+ // Paper start - silent equipping -+ @Override -+ public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem, boolean silent) { -+ super.onEquipItem(slot, oldItem, newItem, silent); -+ // Paper end - silent equipping - if (!this.level().isClientSide()) { - this.reassessWeaponGoal(); - } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Bogged.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Bogged.java.patch index 787f5c998ca1..f01a51ba7da2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Bogged.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Bogged.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/monster/skeleton/Bogged.java +++ b/net/minecraft/world/entity/monster/skeleton/Bogged.java @@ -72,7 +_,19 @@ - ItemStack itemInHand = player.getItemInHand(hand); - if (itemInHand.is(Items.SHEARS) && this.readyForShearing()) { - if (this.level() instanceof ServerLevel serverLevel) { -- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); + ItemStack itemStack = player.getItemInHand(hand); + if (itemStack.is(Items.SHEARS) && this.readyForShearing()) { + if (this.level() instanceof ServerLevel level) { +- this.shear(level, SoundSource.PLAYERS, itemStack); + // CraftBukkit start + // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); -+ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(level, itemStack); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemStack, hand, drops); + if (event != null) { + if (event.isCancelled()) { + return InteractionResult.PASS; @@ -17,42 +17,40 @@ + // Paper end - custom shear drops + } + // CraftBukkit end -+ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); // Paper - custom shear drops ++ this.shear(level, SoundSource.PLAYERS, itemStack, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); - itemInHand.hurtAndBreak(1, player, hand.asEquipmentSlot()); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); } -@@ -125,15 +_,33 @@ +@@ -125,13 +_,33 @@ @Override - public void shear(ServerLevel level, SoundSource source, ItemStack shears) { + public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) { + // Paper start - custom shear drops -+ this.shear(level, source, shears, this.generateDefaultDrops(level, shears)); ++ this.shear(level, soundSource, tool, this.generateDefaultDrops(level, tool)); + } + + @Override -+ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack shears) { ++ public java.util.List generateDefaultDrops(final ServerLevel level, final ItemStack tool) { + final java.util.List drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); -+ this.dropFromShearingLootTable(level, BuiltInLootTables.BOGGED_SHEAR, shears, (ignored, stack) -> { ++ this.dropFromShearingLootTable(level, BuiltInLootTables.BOGGED_SHEAR, tool, (ignored, stack) -> { + drops.add(stack); + }); + return drops; + } + + @Override -+ public void shear(ServerLevel level, SoundSource source, ItemStack shears, java.util.List drops) { ++ public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool, final java.util.List drops) { + // Paper end - custom shear drops - level.playSound(null, this, SoundEvents.BOGGED_SHEAR, source, 1.0F, 1.0F); -- this.spawnShearedMushrooms(level, shears); -+ this.spawnShearedMushrooms(level, shears, drops); // Paper - custom shear drops + level.playSound(null, this, SoundEvents.BOGGED_SHEAR, soundSource, 1.0F, 1.0F); +- this.spawnShearedMushrooms(level, tool); ++ this.spawnShearedMushrooms(level, tool, drops); // Paper - custom shear drops this.setSheared(true); } -- private void spawnShearedMushrooms(ServerLevel level, ItemStack stack) { -- this.dropFromShearingLootTable( -- level, BuiltInLootTables.BOGGED_SHEAR, stack, (serverLevel, itemStack) -> this.spawnAtLocation(serverLevel, itemStack, this.getBbHeight()) -- ); +- private void spawnShearedMushrooms(final ServerLevel level, final ItemStack tool) { +- this.dropFromShearingLootTable(level, BuiltInLootTables.BOGGED_SHEAR, tool, (l, drop) -> this.spawnAtLocation(l, drop, this.getBbHeight())); + // Paper start - custom shear drops -+ private void spawnShearedMushrooms(ServerLevel level, ItemStack stack, java.util.List drops) { ++ private void spawnShearedMushrooms(final ServerLevel level, final ItemStack tool, java.util.List drops) { + this.forceDrops = true; // Paper - Add missing forceDrop toggles + drops.forEach(drop -> this.spawnAtLocation(level, drop, this.getBbHeight())); + this.forceDrops = false; // Paper - Add missing forceDrop toggles diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch index 828eee49ccaf..131968034af6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/Skeleton.java.patch @@ -4,15 +4,15 @@ } protected void doFreezeConversion() { -- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), mob -> { -+ final Stray stray = this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), mob -> { // Paper - Fix issues with mob conversion; reset conversion time to prevent event spam +- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), stray -> { ++ final Stray entity = this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), stray -> { // Paper - Fix issues with mob conversion; reset conversion time to prevent event spam if (!this.isSilent()) { this.level().levelEvent(null, LevelEvent.SOUND_SKELETON_TO_STRAY, this.blockPosition(), 0); } - }); + // Paper start - add spawn and transform reasons + }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN); -+ if (stray == null) { ++ if (entity == null) { + // Reset conversion time to prevent event spam + this.conversionTime = 300; + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch index aabf999cbe62..0ddacc7eb85a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch @@ -12,8 +12,8 @@ @@ -111,6 +_,6 @@ @Override - public boolean canBeAffected(MobEffectInstance effectInstance) { -- return !effectInstance.is(MobEffects.WITHER) && super.canBeAffected(effectInstance); -+ return (!effectInstance.is(net.minecraft.world.effect.MobEffects.WITHER) || !this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton) && super.canBeAffected(effectInstance); // Paper - Add config for mobs immune to default effects + public boolean canBeAffected(final MobEffectInstance newEffect) { +- return !newEffect.is(MobEffects.WITHER) && super.canBeAffected(newEffect); ++ return (!newEffect.is(MobEffects.WITHER) || !this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton) && super.canBeAffected(newEffect); // Paper - Add config for mobs immune to default effects } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/CaveSpider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/CaveSpider.java.patch index cf4e7adfc5c8..f7dea5bb6029 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/CaveSpider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/CaveSpider.java.patch @@ -3,9 +3,9 @@ @@ -38,7 +_,7 @@ } - if (i > 0) { -- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this); -+ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + if (poisonTime > 0) { +- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.POISON, poisonTime * 20, 0), this); ++ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.POISON, poisonTime * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/Spider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/Spider.java.patch index 6448027f791a..32788aa01e11 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/Spider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/spider/Spider.java.patch @@ -12,18 +12,18 @@ @@ -123,7 +_,7 @@ @Override - public boolean canBeAffected(MobEffectInstance effectInstance) { -- return !effectInstance.is(MobEffects.POISON) && super.canBeAffected(effectInstance); -+ return (!effectInstance.is(MobEffects.POISON) || !this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect) && super.canBeAffected(effectInstance); // Paper - Add config for mobs immune to default effects + public boolean canBeAffected(final MobEffectInstance newEffect) { +- return !newEffect.is(MobEffects.POISON) && super.canBeAffected(newEffect); ++ return (!newEffect.is(MobEffects.POISON) || !this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect) && super.canBeAffected(newEffect); // Paper - Add config for mobs immune to default effects } public boolean isClimbing() { @@ -166,7 +_,7 @@ - if (spawnGroupData instanceof Spider.SpiderEffectsGroupData spiderEffectsGroupData) { - Holder holder = spiderEffectsGroupData.effect; - if (holder != null) { -- this.addEffect(new MobEffectInstance(holder, -1)); -+ this.addEffect(new MobEffectInstance(holder, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, level instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit + if (groupData instanceof Spider.SpiderEffectsGroupData spiderEffectsGroupData) { + Holder effect = spiderEffectsGroupData.effect; + if (effect != null) { +- this.addEffect(new MobEffectInstance(effect, -1)); ++ this.addEffect(new MobEffectInstance(effect, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, level instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/AngerManagement.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/AngerManagement.java.patch index 12bd7bec5a60..94d69cd0ece1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/AngerManagement.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/AngerManagement.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/warden/AngerManagement.java +++ b/net/minecraft/world/entity/monster/warden/AngerManagement.java -@@ -146,7 +_,7 @@ +@@ -142,7 +_,7 @@ - public int increaseAnger(Entity entity, int offset) { - boolean flag = !this.angerBySuspect.containsKey(entity); -- int i = this.angerBySuspect.computeInt(entity, (entity1, integer) -> Math.min(150, (integer == null ? 0 : integer) + offset)); -+ int i = this.angerBySuspect.computeInt(entity, (entity1, integer) -> Math.min(150, (integer == null ? 0 : integer) + offset)); // Paper - diff on change (Warden#increaseAngerAt WardenAngerChangeEvent) - if (flag) { - int i1 = this.angerByUuid.removeInt(entity.getUUID()); - i += i1; + public int increaseAnger(final Entity entity, final int increment) { + boolean newSuspect = !this.angerBySuspect.containsKey(entity); +- int currentAnger = this.angerBySuspect.computeInt(entity, (k, anger) -> Math.min(150, (anger == null ? 0 : anger) + increment)); ++ int currentAnger = this.angerBySuspect.computeInt(entity, (k, anger) -> Math.min(150, (anger == null ? 0 : anger) + increment)); // Paper - diff on change (Warden#increaseAngerAt WardenAngerChangeEvent) + if (newSuspect) { + int serializedAnger = this.angerByUuid.removeInt(entity.getUUID()); + currentAnger += serializedAnger; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch index 0cc4dc341d9a..576a3eeafcaa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch @@ -1,27 +1,30 @@ --- a/net/minecraft/world/entity/monster/warden/Warden.java +++ b/net/minecraft/world/entity/monster/warden/Warden.java -@@ -395,7 +_,7 @@ +@@ -404,7 +_,7 @@ - public static void applyDarknessAround(ServerLevel level, Vec3 pos, @Nullable Entity source, int radius) { - MobEffectInstance mobEffectInstance = new MobEffectInstance(MobEffects.DARKNESS, 260, 0, false, false); -- MobEffectUtil.addEffectToPlayersAround(level, source, pos, radius, mobEffectInstance, 200); -+ MobEffectUtil.addEffectToPlayersAround(level, source, pos, radius, mobEffectInstance, 200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.WARDEN); // CraftBukkit - Add EntityPotionEffectEvent.Cause + public static void applyDarknessAround(final ServerLevel level, final Vec3 position, final @Nullable Entity source, final int darknessRadius) { + MobEffectInstance darkness = new MobEffectInstance(MobEffects.DARKNESS, 260, 0, false, false); +- MobEffectUtil.addEffectToPlayersAround(level, source, position, darknessRadius, darkness, 200); ++ MobEffectUtil.addEffectToPlayersAround(level, source, position, darknessRadius, darkness, 200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.WARDEN); // CraftBukkit - Add EntityPotionEffectEvent.Cause } @Override -@@ -439,6 +_,15 @@ +@@ -446,8 +_,17 @@ + } + @VisibleForTesting - public void increaseAngerAt(@Nullable Entity entity, int offset, boolean playListeningSound) { +- public void increaseAngerAt(final @Nullable Entity entity, final int amount, final boolean playSound) { ++ public void increaseAngerAt(final @Nullable Entity entity, int amount, final boolean playSound) { // Paper - Add WardenAngerChangeEvent if (!this.isNoAi() && this.canTargetEntity(entity)) { + // Paper start - Add WardenAngerChangeEvent + int activeAnger = this.angerManagement.getActiveAnger(entity); -+ io.papermc.paper.event.entity.WardenAngerChangeEvent event = new io.papermc.paper.event.entity.WardenAngerChangeEvent((org.bukkit.entity.Warden) this.getBukkitEntity(), entity.getBukkitEntity(), activeAnger, Math.min(150, activeAnger + offset)); ++ io.papermc.paper.event.entity.WardenAngerChangeEvent event = new io.papermc.paper.event.entity.WardenAngerChangeEvent((org.bukkit.entity.Warden) this.getBukkitEntity(), entity.getBukkitEntity(), activeAnger, Math.min(150, activeAnger + amount)); + this.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } -+ offset = event.getNewAnger() - activeAnger; ++ amount = event.getNewAnger() - activeAnger; + // Paper end - Add WardenAngerChangeEvent WardenAi.setDigCooldown(this); - boolean flag = !(this.getTarget() instanceof Player); - int i = this.angerManagement.increaseAnger(entity, offset); + boolean maybeSwitchTarget = !(this.getTarget() instanceof Player); + int newAnger = this.angerManagement.increaseAnger(entity, amount); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch index 1aee8901a3a3..a263f3c521aa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Drowned.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/monster/zombie/Drowned.java +++ b/net/minecraft/world/entity/monster/zombie/Drowned.java -@@ -89,7 +_,7 @@ +@@ -96,7 +_,7 @@ this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Drowned.class).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> this.okTarget(entity))); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (target, level) -> this.okTarget(target))); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); + if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Husk.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Husk.java.patch index ba69c4fabe36..51508102f963 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Husk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Husk.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/entity/monster/zombie/Husk.java +++ b/net/minecraft/world/entity/monster/zombie/Husk.java -@@ -59,7 +_,7 @@ - boolean flag = super.doHurtTarget(level, target); - if (flag && this.getMainHandItem().isEmpty() && target instanceof LivingEntity) { - float effectiveDifficulty = level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); -- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)effectiveDifficulty), this); -+ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)effectiveDifficulty), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit +@@ -67,7 +_,7 @@ + boolean result = super.doHurtTarget(level, target); + if (result && this.getMainHandItem().isEmpty() && target instanceof LivingEntity) { + float difficulty = level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); +- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)difficulty), this); ++ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)difficulty), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } - return flag; -@@ -86,7 +_,7 @@ - spawnGroupData = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); - float specialMultiplier = difficulty.getSpecialMultiplier(); + return result; +@@ -94,7 +_,7 @@ + groupData = super.finalizeSpawn(level, difficulty, spawnReason, groupData); + float difficultyModifier = difficulty.getSpecialMultiplier(); if (spawnReason != EntitySpawnReason.CONVERSION) { -- this.setCanPickUpLoot(random.nextFloat() < 0.55F * specialMultiplier); -+ this.setCanPickUpLoot(level.getLevel().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || random.nextFloat() < 0.55F * specialMultiplier); // Paper - Add world settings for mobs picking up loot +- this.setCanPickUpLoot(random.nextFloat() < 0.55F * difficultyModifier); ++ this.setCanPickUpLoot(level.getLevel().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || random.nextFloat() < 0.55F * difficultyModifier); // Paper - Add world settings for mobs picking up loot } - if (spawnGroupData != null) { + if (groupData != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch index 79a714e53818..ec8291af250e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch @@ -1,17 +1,19 @@ --- a/net/minecraft/world/entity/monster/zombie/Zombie.java +++ b/net/minecraft/world/entity/monster/zombie/Zombie.java -@@ -67,9 +_,7 @@ +@@ -71,8 +_,10 @@ public class Zombie extends Monster { private static final Identifier SPEED_MODIFIER_BABY_ID = Identifier.withDefaultNamespace("baby"); - private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier( - SPEED_MODIFIER_BABY_ID, 0.5, AttributeModifier.Operation.ADD_MULTIPLIED_BASE -- ); -+ private final AttributeModifier babyModifier = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, this.level().paperConfig().entities.behavior.babyZombieMovementModifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); // Paper - Make baby speed configurable ++ // Paper start - Make baby speed configurable ++ private final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier( ++ SPEED_MODIFIER_BABY_ID, this.level().paperConfig().entities.behavior.babyZombieMovementModifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE ++ // Paper end + ); private static final Identifier REINFORCEMENT_CALLER_CHARGE_ID = Identifier.withDefaultNamespace("reinforcement_caller_charge"); private static final AttributeModifier ZOMBIE_REINFORCEMENT_CALLEE_CHARGE = new AttributeModifier( - Identifier.withDefaultNamespace("reinforcement_callee_charge"), -0.05F, AttributeModifier.Operation.ADD_VALUE -@@ -90,13 +_,15 @@ +@@ -96,13 +_,15 @@ private static final boolean DEFAULT_BABY = false; private static final boolean DEFAULT_CAN_BREAK_DOORS = false; private static final int DEFAULT_IN_WATER_TIME = 0; @@ -22,13 +24,13 @@ public int conversionTime; + private boolean shouldBurnInDay = true; // Paper - Add more Zombie API - public Zombie(EntityType type, Level level) { + public Zombie(final EntityType type, final Level level) { super(type, level); + this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty } - public Zombie(Level level) { -@@ -105,7 +_,7 @@ + public Zombie(final Level level) { +@@ -111,7 +_,7 @@ @Override protected void registerGoals() { @@ -37,7 +39,7 @@ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); this.addBehaviourGoals(); -@@ -118,7 +_,7 @@ +@@ -124,7 +_,7 @@ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); @@ -46,10 +48,10 @@ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); } -@@ -172,11 +_,16 @@ +@@ -178,11 +_,16 @@ @Override - protected int getBaseExperienceReward(ServerLevel level) { + protected int getBaseExperienceReward(final ServerLevel level) { + final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward if (this.isBaby()) { this.xpReward = (int)(this.xpReward * 2.5); @@ -64,19 +66,7 @@ } @Override -@@ -184,9 +_,9 @@ - this.getEntityData().set(DATA_BABY_ID, childZombie); - if (this.level() != null && !this.level().isClientSide()) { - AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); -- attribute.removeModifier(SPEED_MODIFIER_BABY_ID); -+ attribute.removeModifier(this.babyModifier.id()); // Paper - Make baby speed configurable - if (childZombie) { -- attribute.addTransientModifier(SPEED_MODIFIER_BABY); -+ attribute.addTransientModifier(this.babyModifier); // Paper - Make baby speed configurable - } - } - } -@@ -227,6 +_,13 @@ +@@ -233,6 +_,13 @@ super.tick(); } @@ -87,21 +77,24 @@ + } + // Paper end - Add more Zombie API + - public void startUnderWaterConversion(int conversionTime) { - this.conversionTime = conversionTime; + public void startUnderWaterConversion(final int time) { + this.conversionTime = time; this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, true); -@@ -240,31 +_,50 @@ +@@ -246,17 +_,28 @@ } - protected void convertToZombieType(ServerLevel level, EntityType entityType) { + protected void convertToZombieType(final ServerLevel level, final EntityType zombieType) { - this.convertTo( + Zombie converted = this.convertTo( // CraftBukkit - entityType, + zombieType, ConversionParams.single(this, true, true), -- zombie -> zombie.handleAttributes(level.getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier()) -- ); +- newZombie -> newZombie.handleAttributes( + // CraftBukkit start -+ zombie -> { zombie.handleAttributes(level.getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier()); }, ++ newZombie -> { newZombie.handleAttributes( + level.getCurrentDifficultyAt(newZombie.blockPosition()).getSpecialMultiplier(), EntitySpawnReason.CONVERSION +- ) +- ); ++ ); }, + org.bukkit.event.entity.EntityTransformEvent.TransformReason.DROWNED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DROWNED); + if (converted == null) { + ((org.bukkit.entity.Zombie) this.getBukkitEntity()).setConversionTime(-1); // CraftBukkit - SPIGOT-5208: End conversion to stop event spam @@ -110,28 +103,30 @@ } @VisibleForTesting - public boolean convertVillagerToZombieVillager(ServerLevel level, Villager villager) { + public boolean convertVillagerToZombieVillager(final ServerLevel level, final Villager villager) { + // CraftBukkit start + return convertVillagerToZombieVillager(level, villager, this.blockPosition(), this.isSilent(), org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.INFECTION) != null; + } + -+ public static @Nullable ZombieVillager convertVillagerToZombieVillager(ServerLevel level, Villager villager, net.minecraft.core.BlockPos blockPosition, boolean silent, org.bukkit.event.entity.EntityTransformEvent.TransformReason transformReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason) { ++ public static @Nullable ZombieVillager convertVillagerToZombieVillager(final ServerLevel level, final Villager villager, final net.minecraft.core.BlockPos blockPosition, boolean silent, org.bukkit.event.entity.EntityTransformEvent.TransformReason transformReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason creatureSpawnReason) { + // CraftBukkit end - ZombieVillager zombieVillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, ConversionParams.single(villager, true, true), mob -> { - mob.finalizeSpawn(level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CONVERSION, new Zombie.ZombieGroupData(false, true)); - mob.setVillagerData(villager.getVillagerData()); - mob.setGossips(villager.getGossips().copy()); - mob.setTradeOffers(villager.getOffers().copy()); - mob.setVillagerXp(villager.getVillagerXp()); -- if (!this.isSilent()) { -- level.levelEvent(null, LevelEvent.SOUND_ZOMBIE_INFECTED, this.blockPosition(), 0); -+ // CraftBukkit start -+ if (!silent) { -+ level.levelEvent(null, LevelEvent.SOUND_ZOMBIE_INFECTED, blockPosition, 0); - } -- }); + ZombieVillager zombieVillager = villager.convertTo( + EntityType.ZOMBIE_VILLAGER, + ConversionParams.single(villager, true, true), +@@ -268,17 +_,24 @@ + zombie.setGossips(villager.getGossips().copy()); + zombie.setTradeOffers(villager.getOffers().copy()); + zombie.setVillagerXp(villager.getVillagerXp()); +- if (!this.isSilent()) { +- level.levelEvent(null, LevelEvent.SOUND_ZOMBIE_INFECTED, this.blockPosition(), 0); ++ // CraftBukkit start ++ if (!silent) { ++ level.levelEvent(null, LevelEvent.SOUND_ZOMBIE_INFECTED, blockPosition, 0); + } +- } +- ); - return zombieVillager != null; -+ }, transformReason, creatureSpawnReason); ++ }, transformReason, creatureSpawnReason); + return zombieVillager; + // CraftBukkit end } @@ -149,31 +144,33 @@ + // Paper end - Add more Zombie API @Override - public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { -@@ -297,13 +_,13 @@ - if (SpawnPlacements.isSpawnPositionOk(type, level, blockPos) - && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.REINFORCEMENT, blockPos, level.random)) { - zombie.setPos(i1, i2, i3); -- if (!level.hasNearbyAlivePlayer(i1, i2, i3, 7.0) -+ if (!level.hasNearbyAlivePlayerThatAffectsSpawning(i1, i2, i3, 7.0) // Paper - affects spawning api - && level.isUnobstructed(zombie) - && level.noCollision(zombie) - && (zombie.canSpawnInLiquids() || !level.containsAnyLiquid(zombie.getBoundingBox()))) { -- zombie.setTarget(target); -+ zombie.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET); // CraftBukkit - zombie.finalizeSpawn(level, level.getCurrentDifficultyAt(zombie.blockPosition()), EntitySpawnReason.REINFORCEMENT, null); -- level.addFreshEntityWithPassengers(zombie); -+ level.addFreshEntityWithPassengers(zombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit + public boolean hurtServer(final ServerLevel level, final DamageSource source, final float damage) { +@@ -311,15 +_,15 @@ + if (SpawnPlacements.isSpawnPositionOk(type, level, spawnPos) + && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.REINFORCEMENT, spawnPos, level.getRandom())) { + reinforcement.setPos(xt, yt, zt); +- if (!level.hasNearbyAlivePlayer(xt, yt, zt, 7.0) ++ if (!level.hasNearbyAlivePlayerThatAffectsSpawning(xt, yt, zt, 7.0) // Paper - affects spawning api + && level.isUnobstructed(reinforcement) + && level.noCollision(reinforcement) + && (reinforcement.canSpawnInLiquids() || !level.containsAnyLiquid(reinforcement.getBoundingBox()))) { +- reinforcement.setTarget(target); ++ reinforcement.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET); // CraftBukkit + reinforcement.finalizeSpawn( + level, level.getCurrentDifficultyAt(reinforcement.blockPosition()), EntitySpawnReason.REINFORCEMENT, null + ); +- level.addFreshEntityWithPassengers(reinforcement); ++ level.addFreshEntityWithPassengers(reinforcement, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit AttributeInstance attribute = this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE); AttributeModifier modifier = attribute.getModifier(REINFORCEMENT_CALLER_CHARGE_ID); - double d = modifier != null ? modifier.amount() : 0.0; -@@ -328,7 +_,12 @@ - if (flag) { - float effectiveDifficulty = level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); - if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < effectiveDifficulty * 0.3F) { -- target.igniteForSeconds(2 * (int)effectiveDifficulty); + double existingAmount = modifier != null ? modifier.amount() : 0.0; +@@ -344,7 +_,12 @@ + if (result) { + float difficulty = level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); + if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < difficulty * 0.3F) { +- target.igniteForSeconds(2 * (int)difficulty); + // CraftBukkit start -+ org.bukkit.event.entity.EntityCombustByEntityEvent event = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), target.getBukkitEntity(), (float) (2 * (int)effectiveDifficulty)); ++ org.bukkit.event.entity.EntityCombustByEntityEvent event = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), target.getBukkitEntity(), (float) (2 * (int)difficulty)); + if (event.callEvent()) { + target.igniteForSeconds(event.getDuration(), false); + } @@ -181,7 +178,7 @@ } } -@@ -390,6 +_,7 @@ +@@ -406,6 +_,7 @@ output.putBoolean("CanBreakDoors", this.canBreakDoors()); output.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); output.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); @@ -189,7 +186,7 @@ } @Override -@@ -404,13 +_,15 @@ +@@ -420,13 +_,15 @@ } else { this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, false); } @@ -197,31 +194,40 @@ } @Override - public boolean killedEntity(ServerLevel level, LivingEntity entity, DamageSource damageSource) { - boolean flag = super.killedEntity(level, entity, damageSource); + public boolean killedEntity(final ServerLevel level, final LivingEntity entity, final DamageSource source) { + boolean perished = super.killedEntity(level, entity, source); - if ((level.getDifficulty() == Difficulty.NORMAL || level.getDifficulty() == Difficulty.HARD) && entity instanceof Villager villager) { - if (level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { + final double fallbackChance = level.getDifficulty() == Difficulty.HARD ? 100 : level.getDifficulty() == Difficulty.NORMAL ? 50 : 0; // Paper - Configurable chance of villager zombie infection - moved up from belows if + if (this.random.nextDouble() * 100 < level.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && entity instanceof Villager villager) { // Paper - Configurable chance of villager zombie infection + if (false && level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { // Paper - Configurable chance of villager zombie infection - moved to "fallbackChance" - return flag; + return perished; } -@@ -445,7 +_,7 @@ - spawnGroupData = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); - float specialMultiplier = difficulty.getSpecialMultiplier(); +@@ -461,7 +_,7 @@ + groupData = super.finalizeSpawn(level, difficulty, spawnReason, groupData); + float difficultyModifier = difficulty.getSpecialMultiplier(); if (spawnReason != EntitySpawnReason.CONVERSION) { -- this.setCanPickUpLoot(random.nextFloat() < 0.55F * specialMultiplier); -+ this.setCanPickUpLoot(level.getLevel().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || random.nextFloat() < 0.55F * specialMultiplier); // Paper - Add world settings for mobs picking up loot +- this.setCanPickUpLoot(random.nextFloat() < 0.55F * difficultyModifier); ++ this.setCanPickUpLoot(level.getLevel().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || random.nextFloat() < 0.55F * difficultyModifier); // Paper - Add world settings for mobs picking up loot } - if (spawnGroupData == null) { -@@ -472,7 +_,7 @@ - chicken1.finalizeSpawn(level, difficulty, EntitySpawnReason.JOCKEY, null); - chicken1.setChickenJockey(true); - this.startRiding(chicken1, false, false); -- level.addFreshEntity(chicken1); -+ level.addFreshEntity(chicken1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit + if (groupData == null) { +@@ -488,7 +_,7 @@ + chicken.finalizeSpawn(level, difficulty, EntitySpawnReason.JOCKEY, null); + chicken.setChickenJockey(true); + this.startRiding(chicken, false, false); +- level.addFreshEntity(chicken); ++ level.addFreshEntity(chicken, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit } } } +@@ -514,7 +_,7 @@ + protected void onOffspringSpawnedFromEgg(final Player spawner, final Mob offspring) { + if (this.level() instanceof ServerLevel serverLevel) { + float difficultyModifier = serverLevel.getCurrentDifficultyAt(offspring.blockPosition()).getSpecialMultiplier(); +- offspring.setCanPickUpLoot(this.random.nextFloat() < 0.55F * difficultyModifier); ++ offspring.setCanPickUpLoot(serverLevel.paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || this.random.nextFloat() < 0.55F * difficultyModifier); // Paper - Add world settings for mobs picking up loot + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch index 3550e14d7231..23251af58f11 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombieVillager.java.patch @@ -1,52 +1,52 @@ --- a/net/minecraft/world/entity/monster/zombie/ZombieVillager.java +++ b/net/minecraft/world/entity/monster/zombie/ZombieVillager.java -@@ -189,12 +_,20 @@ +@@ -200,12 +_,20 @@ } - public void startConverting(@Nullable UUID conversionStarter, int villagerConversionTime) { + public void startConverting(final @Nullable UUID player, final int time) { + // Paper start - missing entity behaviour api - converting without entity event -+ this.startConverting(conversionStarter, villagerConversionTime, true); ++ this.startConverting(player, time, true); + } + -+ public void startConverting(@Nullable UUID conversionStarter, int villagerConversionTime, boolean broadcastEntityEvent) { ++ public void startConverting(@Nullable UUID player, int time, boolean broadcastEntityEvent) { + // Paper end - missing entity behaviour api - converting without entity event - this.conversionStarter = conversionStarter; - this.villagerConversionTime = villagerConversionTime; + this.conversionStarter = player; + this.villagerConversionTime = time; this.getEntityData().set(DATA_CONVERTING_ID, true); - this.removeEffect(MobEffects.WEAKNESS); -- this.addEffect(new MobEffectInstance(MobEffects.STRENGTH, villagerConversionTime, Math.min(this.level().getDifficulty().getId() - 1, 0))); +- this.addEffect(new MobEffectInstance(MobEffects.STRENGTH, time, Math.min(this.level().getDifficulty().getId() - 1, 0))); - this.level().broadcastEntityEvent(this, EntityEvent.ZOMBIE_CONVERTING); + // CraftBukkit start + this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); -+ this.addEffect(new MobEffectInstance(MobEffects.STRENGTH, villagerConversionTime, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); ++ this.addEffect(new MobEffectInstance(MobEffects.STRENGTH, time, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); + // CraftBukkit end + if (broadcastEntityEvent) this.level().broadcastEntityEvent(this, EntityEvent.ZOMBIE_CONVERTING); // Paper - missing entity behaviour api - converting without entity event } @Override -@@ -219,7 +_,7 @@ +@@ -235,7 +_,7 @@ } - private void finishConversion(ServerLevel level) { + private void finishConversion(final ServerLevel level) { - this.convertTo( + Villager converted = this.convertTo( // CraftBukkit EntityType.VILLAGER, ConversionParams.single(this, false, false), - mob -> { -@@ -245,19 +_,24 @@ - mob.finalizeSpawn(level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CONVERSION, null); - mob.refreshBrain(level); + villager -> { +@@ -261,19 +_,24 @@ + villager.finalizeSpawn(level, level.getCurrentDifficultyAt(villager.blockPosition()), EntitySpawnReason.CONVERSION, null); + villager.refreshBrain(level); if (this.conversionStarter != null) { -- Player playerByUuid = level.getPlayerByUUID(this.conversionStarter); -+ Player playerByUuid = level.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate - if (playerByUuid instanceof ServerPlayer) { - CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)playerByUuid, this, mob); - level.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, playerByUuid, mob); +- Player player = level.getPlayerByUUID(this.conversionStarter); ++ Player player = level.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate + if (player instanceof ServerPlayer) { + CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)player, this, villager); + level.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, player, villager); } } -- mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0)); -+ mob.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit +- villager.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0)); ++ villager.addEffect(new MobEffectInstance(MobEffects.NAUSEA, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit if (!this.isSilent()) { level.levelEvent(null, LevelEvent.SOUND_ZOMBIE_CONVERTED, this.blockPosition(), 0); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch index 923e5403fa79..42cdc2e833f7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java +++ b/net/minecraft/world/entity/monster/zombie/ZombifiedPiglin.java -@@ -57,6 +_,7 @@ +@@ -61,6 +_,7 @@ private static final int ALERT_RANGE_Y = 10; private static final UniformInt ALERT_INTERVAL = TimeUtil.rangeOfSeconds(4, 6); private int ticksUntilNextAlert; + private HurtByTargetGoal hurtByTargetGoal; // Paper - fix PigZombieAngerEvent cancellation - public ZombifiedPiglin(EntityType type, Level level) { + public ZombifiedPiglin(final EntityType type, final Level level) { super(type, level); -@@ -68,7 +_,7 @@ +@@ -72,7 +_,7 @@ this.goalSelector.addGoal(1, new SpearUseGoal<>(this, 1.0, 1.0, 10.0F, 2.0F)); this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0, false)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); @@ -17,21 +17,21 @@ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); } -@@ -141,7 +_,7 @@ - .filter(zombifiedPiglin -> zombifiedPiglin != this) - .filter(zombifiedPiglin -> zombifiedPiglin.getTarget() == null) - .filter(zombifiedPiglin -> !zombifiedPiglin.isAlliedTo(this.getTarget())) -- .forEach(zombifiedPiglin -> zombifiedPiglin.setTarget(this.getTarget())); -+ .forEach(zombifiedPiglin -> zombifiedPiglin.setTarget(this.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY)); // CraftBukkit +@@ -145,7 +_,7 @@ + .filter(other -> other != this) + .filter(other -> other.getTarget() == null) + .filter(other -> !other.isAlliedTo(this.getTarget())) +- .forEach(other -> other.setTarget(this.getTarget())); ++ .forEach(other -> other.setTarget(this.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY)); // CraftBukkit } private void playAngerSound() { -@@ -149,18 +_,27 @@ +@@ -153,18 +_,27 @@ } @Override -- public void setTarget(@Nullable LivingEntity target) { -+ public boolean setTarget(@Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit - signature +- public void setTarget(final @Nullable LivingEntity target) { ++ public boolean setTarget(final @Nullable LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.@Nullable TargetReason reason) { // CraftBukkit - signature if (this.getTarget() == null && target != null) { this.playFirstAngerSoundIn = FIRST_ANGER_SOUND_DELAY.sample(this.random); this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch index d18c0f63ded7..80cca6bf31af 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/entity/npc/CatSpawner.java +++ b/net/minecraft/world/entity/npc/CatSpawner.java @@ -65,12 +_,12 @@ - private void spawnCat(BlockPos pos, ServerLevel level, boolean persistent) { + private void spawnCat(final BlockPos spawnPos, final ServerLevel level, final boolean makePersistent) { Cat cat = EntityType.CAT.create(level, EntitySpawnReason.NATURAL); if (cat != null) { -+ cat.snapTo(pos, 0.0F, 0.0F); // Paper - move up - Fix MC-147659 - cat.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.NATURAL, null); - if (persistent) { ++ cat.snapTo(spawnPos, 0.0F, 0.0F); // Paper - move up - Fix MC-147659 + cat.finalizeSpawn(level, level.getCurrentDifficultyAt(spawnPos), EntitySpawnReason.NATURAL, null); + if (makePersistent) { cat.setPersistenceRequired(); } -- cat.snapTo(pos, 0.0F, 0.0F); +- cat.snapTo(spawnPos, 0.0F, 0.0F); level.addFreshEntityWithPassengers(cat); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/InventoryCarrier.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/InventoryCarrier.java.patch index 106c9c66cfb6..c1f34c5bd98e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/InventoryCarrier.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/InventoryCarrier.java.patch @@ -5,19 +5,19 @@ } + // CraftBukkit start -+ ItemStack remaining = new SimpleContainer(inventory).addItem(item); ++ ItemStack remaining = new SimpleContainer(inventory).addItem(itemStack); + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(mob, itemEntity, remaining.getCount()).isCancelled()) { + return; + } + // CraftBukkit end + mob.onItemPickup(itemEntity); - int count = item.getCount(); - ItemStack itemStack = inventory.addItem(item); - mob.take(itemEntity, count - itemStack.getCount()); - if (itemStack.isEmpty()) { + int count = itemStack.getCount(); + ItemStack remainder = inventory.addItem(itemStack); + mob.take(itemEntity, count - remainder.getCount()); + if (remainder.isEmpty()) { - itemEntity.discard(); + itemEntity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { - item.setCount(itemStack.getCount()); + itemStack.setCount(remainder.getCount()); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch index f032420bf2ec..658ada1533ff 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/npc/villager/AbstractVillager.java +++ b/net/minecraft/world/entity/npc/villager/AbstractVillager.java -@@ -43,7 +_,7 @@ - private static final int VILLAGER_INVENTORY_SIZE = 8; +@@ -56,7 +_,7 @@ + private static final EntityDataAccessor DATA_UNHAPPY_COUNTER = SynchedEntityData.defineId(AbstractVillager.class, EntityDataSerializers.INT); private @Nullable Player tradingPlayer; protected @Nullable MerchantOffers offers; - private final SimpleContainer inventory = new SimpleContainer(8); + private final SimpleContainer inventory = new SimpleContainer(8, (org.bukkit.craftbukkit.entity.CraftAbstractVillager) this.getBukkitEntity()); // CraftBukkit - add argument - public AbstractVillager(EntityType type, Level level) { + public AbstractVillager(final EntityType type, final Level level) { super(type, level); -@@ -95,6 +_,20 @@ +@@ -108,6 +_,20 @@ return this.tradingPlayer != null; } @@ -30,8 +30,8 @@ @Override public MerchantOffers getOffers() { if (this.level() instanceof ServerLevel serverLevel) { -@@ -117,11 +_,24 @@ - public void overrideXp(int xp) { +@@ -130,11 +_,24 @@ + public void overrideXp(final int xp) { } + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent @@ -48,7 +48,7 @@ + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent + @Override - public void notifyTrade(MerchantOffer offer) { + public void notifyTrade(final MerchantOffer offer) { - offer.increaseUses(); + // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent this.ambientSoundTime = -this.getAmbientSoundInterval(); @@ -57,25 +57,86 @@ if (this.tradingPlayer instanceof ServerPlayer) { CriteriaTriggers.TRADE.trigger((ServerPlayer)this.tradingPlayer, this, offer.getResult()); } -@@ -225,7 +_,20 @@ - while (i < maxNumbers && !list.isEmpty()) { - MerchantOffer offer = list.remove(this.random.nextInt(list.size())).getOffer(level, this, this.random); +@@ -232,6 +_,11 @@ + protected abstract void updateTrades(ServerLevel level); + + protected void addOffersFromTradeSet(final ServerLevel level, final MerchantOffers offers, final ResourceKey resourceKey) { ++ // Paper start - More vanilla friendly methods to update trades ++ addOffersFromTradeSet(level, offers, resourceKey, -1); ++ } ++ protected void addOffersFromTradeSet(final ServerLevel level, final MerchantOffers offers, final ResourceKey resourceKey, int offerCount) { ++ // Paper end - More vanilla friendly methods to update trades + Optional tradeSetOpt = this.registryAccess().lookupOrThrow(Registries.TRADE_SET).getOptional(resourceKey); + if (tradeSetOpt.isEmpty()) { + LOGGER.debug("Missing expected trade set {}", resourceKey); +@@ -245,17 +_,18 @@ + .create(LootContextParamSets.VILLAGER_TRADE) + ) + .create(tradeSet.randomSequence()); +- int numberOfOffers = tradeSet.calculateNumberOfTrades(lootContext); ++ int numberOfOffers = offerCount != -1 ? offerCount : tradeSet.calculateNumberOfTrades(lootContext); // Paper - More vanilla friendly methods to update trades + if (tradeSet.allowDuplicates()) { +- addOffersFromItemListings(lootContext, offers, tradeSet.getTrades(), numberOfOffers); ++ addOffersFromItemListings(lootContext, offers, tradeSet.getTrades(), numberOfOffers, this); // Paper + } else { +- addOffersFromItemListingsWithoutDuplicates(lootContext, offers, tradeSet.getTrades(), numberOfOffers); ++ addOffersFromItemListingsWithoutDuplicates(lootContext, offers, tradeSet.getTrades(), numberOfOffers, this); // Paper + } + } + } + + private static void addOffersFromItemListings( + final LootContext lootContext, final MerchantOffers merchantOffers, final HolderSet potentialOffers, final int numberOfOffers ++ , AbstractVillager villager // Paper + ) { + int offersFound = 0; + +@@ -267,7 +_,7 @@ + + MerchantOffer offer = villagerTrade.get().value().getOffer(lootContext); if (offer != null) { -- givenMerchantOffers.add(offer); -+ // CraftBukkit start -+ org.bukkit.event.entity.VillagerAcquireTradeEvent event = new org.bukkit.event.entity.VillagerAcquireTradeEvent((org.bukkit.entity.AbstractVillager) this.getBukkitEntity(), offer.asBukkit()); -+ // Suppress during worldgen -+ if (this.valid) { -+ event.callEvent(); -+ } -+ if (!event.isCancelled()) { -+ // Paper start - Fix crash from invalid ingredient list -+ final org.bukkit.craftbukkit.inventory.CraftMerchantRecipe craftMerchantRecipe = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getRecipe()); -+ if (craftMerchantRecipe.getIngredients().isEmpty()) return; -+ givenMerchantOffers.add(craftMerchantRecipe.toMinecraft()); -+ // Paper end - Fix crash from invalid ingredient list -+ } -+ // CraftBukkit end - i++; +- merchantOffers.add(offer); ++ tryAcquireTrade(villager, merchantOffers, offer); // Paper + offersFound++; } } +@@ -275,6 +_,7 @@ + + private static void addOffersFromItemListingsWithoutDuplicates( + final LootContext lootContext, final MerchantOffers merchantOffers, final HolderSet potentialOffers, final int numberOfOffers ++ , final AbstractVillager villager // Paper + ) { + List> leftoverOffers = Lists.newArrayList(potentialOffers); + int offersFound = 0; +@@ -283,11 +_,30 @@ + Holder villagerTrade = leftoverOffers.remove(lootContext.getRandom().nextInt(leftoverOffers.size())); + MerchantOffer offer = villagerTrade.value().getOffer(lootContext); + if (offer != null) { +- merchantOffers.add(offer); ++ tryAcquireTrade(villager, merchantOffers, offer); // Paper + offersFound++; + } + } + } ++ ++ // Paper start ++ private static void tryAcquireTrade(final AbstractVillager villager, final MerchantOffers merchantOffers, MerchantOffer offer) { ++ // CraftBukkit start ++ org.bukkit.event.entity.VillagerAcquireTradeEvent event = new org.bukkit.event.entity.VillagerAcquireTradeEvent((org.bukkit.entity.AbstractVillager) villager.getBukkitEntity(), offer.asBukkit()); ++ // Suppress during worldgen ++ if (villager.valid) { ++ event.callEvent(); ++ } ++ if (!event.isCancelled()) { ++ // Paper start - Fix crash from invalid ingredient list ++ final org.bukkit.craftbukkit.inventory.CraftMerchantRecipe craftMerchantRecipe = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getRecipe()); ++ if (craftMerchantRecipe.getIngredients().isEmpty()) return; ++ merchantOffers.add(craftMerchantRecipe.toMinecraft()); ++ // Paper end - Fix crash from invalid ingredient list ++ } ++ // CraftBukkit end ++ } ++ // Paper end + + @Override + public Vec3 getRopeHoldPosition(final float partialTickTime) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch index 9065f2e46d63..d9a7bbd649b9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/npc/villager/Villager.java +++ b/net/minecraft/world/entity/npc/villager/Villager.java -@@ -287,7 +_,7 @@ +@@ -262,7 +_,7 @@ this.increaseProfessionLevelOnUpdate = false; } @@ -9,140 +9,135 @@ } } -@@ -396,7 +_,12 @@ +@@ -376,7 +_,12 @@ this.updateDemand(); - for (MerchantOffer merchantOffer : this.getOffers()) { -- merchantOffer.resetUses(); + for (MerchantOffer offer : this.getOffers()) { +- offer.resetUses(); + // CraftBukkit start -+ org.bukkit.event.entity.VillagerReplenishTradeEvent event = new org.bukkit.event.entity.VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantOffer.asBukkit()); ++ org.bukkit.event.entity.VillagerReplenishTradeEvent event = new org.bukkit.event.entity.VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), offer.asBukkit()); + if (event.callEvent()) { -+ merchantOffer.resetUses(); ++ offer.resetUses(); + } + // CraftBukkit end } this.resendOffersToTradingPlayer(); -@@ -452,7 +_,12 @@ - int i = 2 - this.numberOfRestocksToday; - if (i > 0) { - for (MerchantOffer merchantOffer : this.getOffers()) { -- merchantOffer.resetUses(); +@@ -437,7 +_,12 @@ + int missedUpdates = 2 - this.numberOfRestocksToday; + if (missedUpdates > 0) { + for (MerchantOffer offer : this.getOffers()) { +- offer.resetUses(); + // CraftBukkit start -+ org.bukkit.event.entity.VillagerReplenishTradeEvent event = new org.bukkit.event.entity.VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantOffer.asBukkit()); ++ org.bukkit.event.entity.VillagerReplenishTradeEvent event = new org.bukkit.event.entity.VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), offer.asBukkit()); + if (event.callEvent()) { -+ merchantOffer.resetUses(); ++ offer.resetUses(); + } + // CraftBukkit end } } -@@ -473,6 +_,7 @@ - int playerReputation = this.getPlayerReputation(player); - if (playerReputation != 0) { - for (MerchantOffer merchantOffer : this.getOffers()) { -+ if (merchantOffer.ignoreDiscounts) continue; // Paper - Add ignore discounts API - merchantOffer.addToSpecialPriceDiff(-Mth.floor(playerReputation * merchantOffer.getPriceMultiplier())); +@@ -458,6 +_,7 @@ + int reputation = this.getPlayerReputation(player); + if (reputation != 0) { + for (MerchantOffer offer : this.getOffers()) { ++ if (offer.ignoreDiscounts) continue; // Paper - Add ignore discounts API + offer.addToSpecialPriceDiff(-Mth.floor(reputation * offer.getPriceMultiplier())); } } -@@ -482,6 +_,7 @@ +@@ -467,6 +_,7 @@ int amplifier = effect.getAmplifier(); - for (MerchantOffer merchantOffer1 : this.getOffers()) { -+ if (merchantOffer1.ignoreDiscounts) continue; // Paper - Add ignore discounts API - double d = 0.3 + 0.0625 * amplifier; - int i = (int)Math.floor(d * merchantOffer1.getBaseCostA().getCount()); - merchantOffer1.addToSpecialPriceDiff(-Math.max(i, 1)); -@@ -589,7 +_,7 @@ + for (MerchantOffer offer : this.getOffers()) { ++ if (offer.ignoreDiscounts) continue; // Paper - Add ignore discounts API + double modifier = 0.3 + 0.0625 * amplifier; + int costReduction = (int)Math.floor(modifier * offer.getBaseCostA().getCount()); + offer.addToSpecialPriceDiff(-Math.max(costReduction, 1)); +@@ -582,7 +_,7 @@ } if (offer.shouldRewardExp()) { -- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), i)); -+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper +- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), popXp)); ++ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), popXp, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper } } -@@ -607,7 +_,7 @@ +@@ -600,7 +_,7 @@ @Override - public void die(DamageSource damageSource) { -- LOGGER.info("Villager {} died, message: '{}'", this, damageSource.getLocalizedDeathMessage(this).getString()); -+ if (org.spigotmc.SpigotConfig.logVillagerDeaths) LOGGER.info("Villager {} died, message: '{}'", this, damageSource.getLocalizedDeathMessage(this).getString()); // Spigot - Entity entity = damageSource.getEntity(); - if (entity != null) { - this.tellWitnessesThatIWasMurdered(entity); -@@ -706,7 +_,7 @@ - return VillagerData.canLevelUp(level) && this.villagerXp >= VillagerData.getMaxXpPerLevel(level); + public void die(final DamageSource source) { +- LOGGER.info("Villager {} died, message: '{}'", this, source.getLocalizedDeathMessage(this).getString()); ++ if (org.spigotmc.SpigotConfig.logVillagerDeaths) LOGGER.info("Villager {} died, message: '{}'", this, source.getLocalizedDeathMessage(this).getString()); // Spigot + Entity murderer = source.getEntity(); + if (murderer != null) { + this.tellWitnessesThatIWasMurdered(murderer); +@@ -699,7 +_,7 @@ + return VillagerData.canLevelUp(currentLevel) && this.villagerXp >= VillagerData.getMaxXpPerLevel(currentLevel); } -- private void increaseMerchantCareer(ServerLevel level) { -+ public void increaseMerchantCareer(ServerLevel level) { // Paper - public +- private void increaseMerchantCareer(final ServerLevel level) { ++ public void increaseMerchantCareer(final ServerLevel level) { // Paper - public this.setVillagerData(this.getVillagerData().withLevel(this.getVillagerData().level() + 1)); this.updateTrades(level); } -@@ -773,12 +_,19 @@ +@@ -762,12 +_,19 @@ @Override - public void thunderHit(ServerLevel level, LightningBolt lightning) { + public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { if (level.getDifficulty() != Difficulty.PEACEFUL) { -- LOGGER.info("Villager {} was struck by lightning {}.", this, lightning); +- LOGGER.info("Villager {} was struck by lightning {}.", this, lightningBolt); + // Paper - Add EntityZapEvent; move log down, event can cancel - Witch witch = this.convertTo(EntityType.WITCH, ConversionParams.single(this, false, false), witch1 -> { + Witch witch = this.convertTo(EntityType.WITCH, ConversionParams.single(this, false, false), w -> { + // Paper start - Add EntityZapEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityZapEvent(this, lightning, witch1).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityZapEvent(this, lightningBolt, w).isCancelled()) { + return false; + } -+ if (org.spigotmc.SpigotConfig.logVillagerDeaths) LOGGER.info("Villager {} was struck by lightning {}.", this, lightning); // Move down ++ if (org.spigotmc.SpigotConfig.logVillagerDeaths) LOGGER.info("Villager {} was struck by lightning {}.", this, lightningBolt); // Move down + // Paper end - Add EntityZapEvent - witch1.finalizeSpawn(level, level.getCurrentDifficultyAt(witch1.blockPosition()), EntitySpawnReason.CONVERSION, null); - witch1.setPersistenceRequired(); + w.finalizeSpawn(level, level.getCurrentDifficultyAt(w.blockPosition()), EntitySpawnReason.CONVERSION, null); + w.setPersistenceRequired(); this.releaseAllPois(); - }); -+ return true; // Paper start - Add EntityZapEvent ++ return true; // Paper - Add EntityZapEvent + }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.LIGHTNING, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit if (witch == null) { - super.thunderHit(level, lightning); + super.thunderHit(level, lightningBolt); } -@@ -818,6 +_,12 @@ +@@ -807,15 +_,24 @@ @Override - protected void updateTrades(ServerLevel level) { + protected void updateTrades(final ServerLevel level) { + // Paper start - More vanilla friendly methods to update trades -+ this.updateTrades(TRADES_PER_LEVEL); ++ this.updateTrades(-1); + } + + public boolean updateTrades(int amount) { ++ final ServerLevel level = (net.minecraft.server.level.ServerLevel) this.level(); + // Paper end - More vanilla friendly methods to update trades - VillagerData villagerData = this.getVillagerData(); - ResourceKey resourceKey = villagerData.profession().unwrapKey().orElse(null); - if (resourceKey != null) { -@@ -833,13 +_,15 @@ - VillagerTrades.ItemListing[] itemListings = map1.get(villagerData.level()); - if (itemListings != null) { - MerchantOffers offers = this.getOffers(); -- this.addOffersFromItemListings(level, offers, itemListings, 2); -+ this.addOffersFromItemListings((net.minecraft.server.level.ServerLevel) this.level(), offers, itemListings, amount); // Paper - More vanilla friendly methods to update trades - if (SharedConstants.DEBUG_UNLOCK_ALL_TRADES && villagerData.level() < map1.size()) { -- this.increaseMerchantCareer(level); -+ this.increaseMerchantCareer((net.minecraft.server.level.ServerLevel) this.level()); - } -+ return true; // Paper - More vanilla friendly methods to update trades - } + VillagerData data = this.getVillagerData(); + VillagerProfession profession = data.profession().value(); + ResourceKey trades = profession.getTrades(data.level()); + if (trades != null) { +- this.addOffersFromTradeSet(level, this.getOffers(), trades); ++ this.addOffersFromTradeSet(level, this.getOffers(), trades, amount); // Paper - More vanilla friendly methods to update trades + if (SharedConstants.DEBUG_UNLOCK_ALL_TRADES && data.level() < 5) { + this.increaseMerchantCareer(level); } ++ return true; // Paper - More vanilla friendly methods to update trades } + return false; // Paper - More vanilla friendly methods to update trades } - public void gossip(ServerLevel level, Villager target, long gameTime) { -@@ -868,7 +_,7 @@ - List entitiesOfClass = level.getEntitiesOfClass(Villager.class, aabb); - List list = entitiesOfClass.stream().filter(villager -> villager.wantsToSpawnGolem(gameTime)).limit(5L).toList(); - if (list.size() >= minVillagerAmount) { + public void gossip(final ServerLevel level, final Villager target, final long timestamp) { +@@ -847,7 +_,7 @@ + .limit(5L) + .toList(); + if (nearbyVillagersThatWantAGolem.size() >= villagersNeededToAgree) { - if (!SpawnUtil.trySpawnMob( + if (SpawnUtil.trySpawnMob( // Paper - Set Golem Last Seen to stop it from spawning another one - switch to isPresent EntityType.IRON_GOLEM, EntitySpawnReason.MOB_SUMMONED, level, -@@ -877,9 +_,11 @@ +@@ -856,9 +_,11 @@ 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, @@ -153,6 +148,6 @@ ) - .isEmpty()) { + .isPresent()) { // Paper - Set Golem Last Seen to stop it from spawning another one - switch to isPresent - entitiesOfClass.forEach(GolemSensor::golemDetected); + nearbyVillagers.forEach(GolemSensor::golemDetected); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/VillagerTrades.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/VillagerTrades.java.patch deleted file mode 100644 index 3df5d43063e8..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/VillagerTrades.java.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/net/minecraft/world/entity/npc/villager/VillagerTrades.java -+++ b/net/minecraft/world/entity/npc/villager/VillagerTrades.java -@@ -1737,7 +_,8 @@ - - @Override - public @Nullable MerchantOffer getOffer(ServerLevel level, Entity trader, RandomSource random) { -- BlockPos blockPos = level.findNearestMapStructure(this.destination, trader.blockPosition(), 100, true); -+ if (!level.paperConfig().environment.treasureMaps.enabled) return null; // Paper - Configurable cartographer treasure maps -+ BlockPos blockPos = level.findNearestMapStructure(this.destination, trader.blockPosition(), 100, !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager); // Paper - Configurable cartographer treasure maps - if (blockPos != null) { - ItemStack itemStack = MapItem.create(level, blockPos.getX(), blockPos.getZ(), (byte)2, true, true); - MapItem.renderBiomePreviewMap(level, itemStack); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch index ba03df93c684..0c52d50e362a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch @@ -9,36 +9,35 @@ + public boolean canDrinkMilk = true; + // Paper end - Add more WanderingTrader API - public WanderingTrader(EntityType type, Level level) { + public WanderingTrader(final EntityType type, final Level level) { super(type, level); -@@ -67,7 +_,7 @@ +@@ -67,14 +_,14 @@ this, PotionContents.createItemStack(Items.POTION, Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, -- wanderingTrader -> this.level().isDarkOutside() && !wanderingTrader.isInvisible() -+ wanderingTrader -> this.canDrinkPotion && this.level().isDarkOutside() && !wanderingTrader.isInvisible() // Paper - Add more WanderingTrader API +- e -> this.level().isDarkOutside() && !e.isInvisible() ++ e -> this.canDrinkPotion && this.level().isDarkOutside() && !e.isInvisible() // Paper - Add more WanderingTrader API ) ); this.goalSelector -@@ -77,7 +_,7 @@ - this, - new ItemStack(Items.MILK_BUCKET), - SoundEvents.WANDERING_TRADER_REAPPEARED, -- wanderingTrader -> this.level().isBrightOutside() && wanderingTrader.isInvisible() -+ wanderingTrader -> this.canDrinkMilk && this.level().isBrightOutside() && wanderingTrader.isInvisible() // Paper - Add more WanderingTrader API + .addGoal( + 0, + new UseItemGoal<>( +- this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, e -> this.level().isBrightOutside() && e.isInvisible() ++ this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, e -> this.canDrinkMilk && this.level().isBrightOutside() && e.isInvisible() // Paper - Add more WanderingTrader API ) ); this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); -@@ -164,7 +_,7 @@ - protected void rewardTradeXp(MerchantOffer offer) { +@@ -159,7 +_,7 @@ + protected void rewardTradeXp(final MerchantOffer offer) { if (offer.shouldRewardExp()) { - int i = 3 + this.random.nextInt(4); -- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), i)); -+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper + int popXp = 3 + this.random.nextInt(4); +- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), popXp)); ++ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), popXp, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper } } -@@ -216,7 +_,7 @@ +@@ -211,7 +_,7 @@ private void maybeDespawn() { if (this.despawnDelay > 0 && !this.isTrading() && --this.despawnDelay == 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch index f88caff4d5cc..1c205cd062e8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch @@ -1,60 +1,43 @@ --- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java +++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java -@@ -38,36 +_,45 @@ +@@ -37,30 +_,38 @@ - public WanderingTraderSpawner(ServerLevelData serverLevelData) { - this.serverLevelData = serverLevelData; + public WanderingTraderSpawner(final SavedDataStorage savedDataStorage) { + this.savedDataStorage = savedDataStorage; - this.tickDelay = 1200; -- this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay(); -- this.spawnChance = serverLevelData.getWanderingTraderSpawnChance(); -- if (this.spawnDelay == 0 && this.spawnChance == 0) { -- this.spawnDelay = 24000; -- serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); -- this.spawnChance = 25; -- serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); -- } -+ // Paper start - Add Wandering Trader spawn rate config options -+ this.tickDelay = Integer.MIN_VALUE; -+ // this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay(); -+ // this.spawnChance = serverLevelData.getWanderingTraderSpawnChance(); -+ // if (this.spawnDelay == 0 && this.spawnChance == 0) { -+ // this.spawnDelay = 24000; -+ // serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); -+ // this.spawnChance = 25; -+ // serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); -+ // } -+ // Paper end - Add Wandering Trader spawn rate config options ++ this.tickDelay = Integer.MIN_VALUE; // Paper - Add Wandering Trader spawn rate config options + this.traderData = null; } @Override - public void tick(ServerLevel level, boolean spawnEnemies) { + public void tick(final ServerLevel level, final boolean spawnEnemies) { + // Paper start - Add Wandering Trader spawn rate config options + if (this.tickDelay == Integer.MIN_VALUE) { + this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; -+ this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; ++ WanderingTraderData data = this.getTraderData(); ++ data.setSpawnDelay(level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength); ++ data.setSpawnChance(level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin); + } if (level.getGameRules().get(GameRules.SPAWN_WANDERING_TRADERS)) { - if (--this.tickDelay <= 0) { - this.tickDelay = 1200; -- this.spawnDelay -= 1200; -- this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); + if (this.tickDelay - 1 <= 0) { // Paper - Prevent tickDelay going below 0 + this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ this.spawnDelay = this.spawnDelay - level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways - if (this.spawnDelay <= 0) { -- this.spawnDelay = 24000; -+ this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; - int i = this.spawnChance; -- this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75); -- this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); -+ this.spawnChance = Mth.clamp(this.spawnChance + level.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); -+ //this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways - if (this.random.nextInt(100) <= i) { + WanderingTraderData data = this.getTraderData(); +- int spawnDelay = data.spawnDelay() - 1200; ++ int spawnDelay = data.spawnDelay() - level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; + data.setSpawnDelay(spawnDelay); + if (spawnDelay <= 0) { +- data.setSpawnDelay(24000); ++ data.setSpawnDelay(level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength); + int chanceToSpawn = data.spawnChance(); +- int newSpawnChance = Mth.clamp(chanceToSpawn + 25, 25, 75); ++ int newSpawnChance = Mth.clamp(chanceToSpawn + level.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); + data.setSpawnChance(newSpawnChance); + if (this.random.nextInt(100) <= chanceToSpawn) { if (this.spawn(level)) { -- this.spawnChance = 25; -+ this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; +- data.setSpawnChance(25); ++ data.setSpawnChance(level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin); + // Paper end - Add Wandering Trader spawn rate config options } } @@ -64,29 +47,28 @@ } } -@@ -89,14 +_,14 @@ +@@ -90,13 +_,13 @@ return false; } -- WanderingTrader wanderingTrader = EntityType.WANDERING_TRADER.spawn(level, blockPos2, EntitySpawnReason.EVENT); -+ WanderingTrader wanderingTrader = EntityType.WANDERING_TRADER.spawn(level, trader -> trader.setDespawnDelay(48000), blockPos2, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called - if (wanderingTrader != null) { - for (int i1 = 0; i1 < 2; i1++) { - this.tryToSpawnLlamaFor(level, wanderingTrader, 4); +- WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, spawnPosition, EntitySpawnReason.EVENT); ++ WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, wanderingTrader -> wanderingTrader.setDespawnDelay(48000), spawnPosition, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called + if (trader != null) { + for (int i = 0; i < 2; i++) { + this.tryToSpawnLlamaFor(level, trader, 4); } - this.serverLevelData.setWanderingTraderId(wanderingTrader.getUUID()); -- wanderingTrader.setDespawnDelay(48000); -+ // wanderingTrader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent - wanderingTrader.setWanderTarget(blockPos1); - wanderingTrader.setHomeTo(blockPos1, 16); +- trader.setDespawnDelay(48000); ++ // trader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent + trader.setWanderTarget(referencePos); + trader.setHomeTo(referencePos, 16); return true; @@ -110,7 +_,7 @@ - private void tryToSpawnLlamaFor(ServerLevel level, WanderingTrader trader, int maxDistance) { - BlockPos blockPos = this.findSpawnPositionNear(level, trader.blockPosition(), maxDistance); - if (blockPos != null) { -- TraderLlama traderLlama = EntityType.TRADER_LLAMA.spawn(level, blockPos, EntitySpawnReason.EVENT); -+ TraderLlama traderLlama = EntityType.TRADER_LLAMA.spawn(level, blockPos, EntitySpawnReason.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit - if (traderLlama != null) { - traderLlama.setLeashedTo(trader, true); + private void tryToSpawnLlamaFor(final ServerLevel level, final WanderingTrader trader, final int radius) { + BlockPos spawnPosition = this.findSpawnPositionNear(level, trader.blockPosition(), radius); + if (spawnPosition != null) { +- TraderLlama llama = EntityType.TRADER_LLAMA.spawn(level, spawnPosition, EntitySpawnReason.EVENT); ++ TraderLlama llama = EntityType.TRADER_LLAMA.spawn(level, spawnPosition, EntitySpawnReason.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit + if (llama != null) { + llama.setLeashedTo(trader, true); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Inventory.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Inventory.java.patch index 2680b11436cb..086aeec20bba 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Inventory.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Inventory.java.patch @@ -79,18 +79,18 @@ + } + // Paper end - add fields and methods - public Inventory(Player player, EntityEquipment equipment) { + public Inventory(final Player player, final EntityEquipment equipment) { this.player = player; @@ -93,10 +_,39 @@ - private boolean hasRemainingSpaceForItem(ItemStack destination, ItemStack origin) { - return !destination.isEmpty() -- && ItemStack.isSameItemSameComponents(destination, origin) - && destination.isStackable() -- && destination.getCount() < this.getMaxStackSize(destination); + private boolean hasRemainingSpaceForItem(final ItemStack slotItemStack, final ItemStack newItemStack) { + return !slotItemStack.isEmpty() +- && ItemStack.isSameItemSameComponents(slotItemStack, newItemStack) + && slotItemStack.isStackable() +- && slotItemStack.getCount() < this.getMaxStackSize(slotItemStack); - } -+ && destination.getCount() < this.getMaxStackSize(destination) -+ && ItemStack.isSameItemSameComponents(destination, origin); // Paper - check if itemstack is stackable first ++ && slotItemStack.getCount() < this.getMaxStackSize(slotItemStack) ++ && ItemStack.isSameItemSameComponents(slotItemStack, newItemStack); // Paper - check if itemstack is stackable first + } + + // CraftBukkit start - Watch method above! :D @@ -128,25 +128,25 @@ return -1; } -- public void addAndPickItem(ItemStack stack) { +- public void addAndPickItem(final ItemStack itemStack) { - this.setSelectedSlot(this.getSuitableHotbarSlot()); + // Paper start - Add PlayerPickItemEvent -+ public void addAndPickItem(ItemStack stack, final int targetSlot) { ++ public void addAndPickItem(final ItemStack itemStack, final int targetSlot) { + this.setSelectedSlot(targetSlot); + // Paper end - Add PlayerPickItemEvent if (!this.items.get(this.selected).isEmpty()) { int freeSlot = this.getFreeSlot(); if (freeSlot != -1) { @@ -120,8 +_,10 @@ - this.items.set(this.selected, stack); + this.items.set(this.selected, itemStack); } -- public void pickSlot(int index) { +- public void pickSlot(final int slot) { - this.setSelectedSlot(this.getSuitableHotbarSlot()); + // Paper start - Add PlayerPickItemEvent -+ public void pickSlot(int index, final int targetSlot) { ++ public void pickSlot(final int slot, final int targetSlot) { + this.setSelectedSlot(targetSlot); + // Paper end - Add PlayerPickItemEvent - ItemStack itemStack = this.items.get(this.selected); - this.items.set(this.selected, this.items.get(index)); - this.items.set(index, itemStack); + ItemStack tmp = this.items.get(this.selected); + this.items.set(this.selected, this.items.get(slot)); + this.items.set(slot, tmp); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index e45bd8c05b06..c8e25d11aff8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -151,7 +_,7 @@ - private static final int DEFAULT_CURRENT_IMPULSE_CONTEXT_RESET_GRACE_TIME = 0; +@@ -150,7 +_,7 @@ + private static final int DEFAULT_SCORE = 0; public static final float CREATIVE_ENTITY_INTERACTION_RANGE_MODIFIER_VALUE = 2.0F; - final Inventory inventory; + private final Inventory inventory; - protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer(); + protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer(this); // CraftBukkit - add "this" to constructor public final InventoryMenu inventoryMenu; public AbstractContainerMenu containerMenu; protected FoodData foodData = new FoodData(); -@@ -177,6 +_,18 @@ - public @Nullable Entity currentExplosionCause; - private boolean ignoreFallDamageFromCurrentImpulse = false; - private int currentImpulseContextResetGraceTime = 0; +@@ -172,6 +_,18 @@ + private Optional lastDeathLocation = Optional.empty(); + public @Nullable FishingHook fishing; + public float hurtDir; + public boolean affectsSpawning = true; // Paper - Affects Spawning API + public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage + @@ -26,9 +26,9 @@ + } + // CraftBukkit end - public Player(Level level, GameProfile gameProfile) { + public Player(final Level level, final GameProfile gameProfile) { super(EntityType.PLAYER, level); -@@ -244,6 +_,13 @@ +@@ -238,6 +_,13 @@ if (this.isSleeping()) { this.sleepCounter++; @@ -42,16 +42,16 @@ if (this.sleepCounter > 100) { this.sleepCounter = 100; } -@@ -273,7 +_,7 @@ - ItemStack mainHandItem = this.getMainHandItem(); - if (!ItemStack.matches(this.lastItemInMainHand, mainHandItem)) { - if (!ItemStack.isSameItem(this.lastItemInMainHand, mainHandItem)) { +@@ -267,7 +_,7 @@ + ItemStack mainHandItemStack = this.getMainHandItem(); + if (!ItemStack.matches(this.lastItemInMainHand, mainHandItemStack)) { + if (!ItemStack.isSameItem(this.lastItemInMainHand, mainHandItemStack)) { - this.resetAttackStrengthTicker(); + this.resetAttackStrengthTicker(); // Paper - diff on change (detectEquipmentUpdates override) } - this.lastItemInMainHand = mainHandItem.copy(); -@@ -327,7 +_,7 @@ + this.lastItemInMainHand = mainHandItemStack.copy(); +@@ -318,7 +_,7 @@ } private void turtleHelmetTick() { @@ -59,8 +59,8 @@ + this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TURTLE_HELMET); // CraftBukkit } - private boolean isEquipped(Item item) { -@@ -428,6 +_,18 @@ + private boolean isEquipped(final Item item) { +@@ -419,6 +_,18 @@ } } @@ -79,7 +79,7 @@ public void closeContainer() { this.containerMenu = this.inventoryMenu; } -@@ -439,8 +_,14 @@ +@@ -430,8 +_,14 @@ public void rideTick() { if (!this.level().isClientSide() && this.wantsToStopRiding() && this.isPassenger()) { this.stopRiding(); @@ -96,27 +96,27 @@ super.rideTick(); } } -@@ -699,10 +_,10 @@ +@@ -684,10 +_,10 @@ if (this.isDeadOrDying()) { return false; } else { - this.removeEntitiesOnShoulder(); + // this.removeEntitiesOnShoulder(); // CraftBukkit - moved down - if (damageSource.scalesWithDifficulty()) { + if (source.scalesWithDifficulty()) { if (level.getDifficulty() == Difficulty.PEACEFUL) { -- amount = 0.0F; -+ return false; // CraftBukkit - f = 0.0f -> return false +- damage = 0.0F; ++ return false; // CraftBukkit - damage = 0.0F -> return false } if (level.getDifficulty() == Difficulty.EASY) { -@@ -714,7 +_,14 @@ +@@ -699,7 +_,14 @@ } } -- return amount != 0.0F && super.hurtServer(level, damageSource, amount); -+ // return amount != 0.0F && super.hurtServer(level, damageSource, amount); +- return damage != 0.0F && super.hurtServer(level, source, damage); ++ // return damage != 0.0F && super.hurtServer(level, source, damage); + // CraftBukkit start - Don't filter out 0 damage -+ boolean damaged = super.hurtServer(level, damageSource, amount); ++ boolean damaged = super.hurtServer(level, source, damage); + if (damaged) { + this.removeEntitiesOnShoulder(); + } @@ -125,35 +125,35 @@ } } } -@@ -726,7 +_,7 @@ +@@ -711,7 +_,7 @@ BlocksAttacks blocksAttacks = itemBlockingWith != null ? itemBlockingWith.get(DataComponents.BLOCKS_ATTACKS) : null; - float secondsToDisableBlocking = entity.getSecondsToDisableBlocking(); + float secondsToDisableBlocking = attacker.getSecondsToDisableBlocking(); if (secondsToDisableBlocking > 0.0F && blocksAttacks != null) { - blocksAttacks.disable(level, this, secondsToDisableBlocking, itemBlockingWith); -+ blocksAttacks.disable(level, this, secondsToDisableBlocking, itemBlockingWith, entity); // Paper - Add PlayerShieldDisableEvent ++ blocksAttacks.disable(level, this, secondsToDisableBlocking, itemBlockingWith, attacker); // Paper - Add PlayerShieldDisableEvent } } -@@ -736,9 +_,29 @@ +@@ -721,9 +_,29 @@ } - public boolean canHarmPlayer(Player other) { + public boolean canHarmPlayer(final Player target) { - Team team = this.getTeam(); -- Team team1 = other.getTeam(); -- return team == null || !team.isAlliedTo(team1) || team.isAllowFriendlyFire(); +- Team otherTeam = target.getTeam(); +- return team == null || !team.isAlliedTo(otherTeam) || team.isAllowFriendlyFire(); + // CraftBukkit start - Change to check OTHER player's scoreboard team according to API + // To summarize this method's logic, it's "Can parameter hurt this" + org.bukkit.scoreboard.Team team; -+ if (other instanceof ServerPlayer) { -+ ServerPlayer thatPlayer = (ServerPlayer) other; ++ if (target instanceof ServerPlayer) { ++ ServerPlayer thatPlayer = (ServerPlayer) target; + team = thatPlayer.getBukkitEntity().getScoreboard().getPlayerTeam(thatPlayer.getBukkitEntity()); + if (team == null || team.allowFriendlyFire()) { + return true; + } + } else { + // This should never be called, but is implemented anyway -+ org.bukkit.OfflinePlayer thisPlayer = other.level().getCraftServer().getOfflinePlayer(other.getScoreboardName()); -+ team = other.level().getCraftServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer); ++ org.bukkit.OfflinePlayer thisPlayer = target.level().getCraftServer().getOfflinePlayer(target.getScoreboardName()); ++ team = target.level().getCraftServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer); + if (team == null || team.allowFriendlyFire()) { + return true; + } @@ -167,30 +167,30 @@ } @Override -@@ -752,7 +_,12 @@ +@@ -737,7 +_,12 @@ } @Override -- protected void actuallyHurt(ServerLevel level, DamageSource damageSource, float amount) { +- protected void actuallyHurt(final ServerLevel level, final DamageSource source, float dmg) { + // CraftBukkit start -+ protected boolean actuallyHurt(ServerLevel level, DamageSource damageSource, float amount, org.bukkit.event.entity.EntityDamageEvent event) { // void -> boolean ++ protected boolean actuallyHurt(final ServerLevel level, final DamageSource source, float dmg, org.bukkit.event.entity.EntityDamageEvent event) { // void -> boolean + if (true) { -+ return super.actuallyHurt(level, damageSource, amount, event); ++ return super.actuallyHurt(level, source, dmg, event); + } + // CraftBukkit end - if (!this.isInvulnerableTo(level, damageSource)) { - amount = this.getDamageAfterArmorAbsorb(damageSource, amount); - amount = this.getDamageAfterMagicAbsorb(damageSource, amount); -@@ -764,7 +_,7 @@ + if (!this.isInvulnerableTo(level, source)) { + dmg = this.getDamageAfterArmorAbsorb(source, dmg); + dmg = this.getDamageAfterMagicAbsorb(source, dmg); +@@ -749,7 +_,7 @@ } if (var8 != 0.0F) { -- this.causeFoodExhaustion(damageSource.getFoodExhaustion()); -+ this.causeFoodExhaustion(damageSource.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent - this.getCombatTracker().recordDamage(damageSource, var8); +- this.causeFoodExhaustion(source.getFoodExhaustion()); ++ this.causeFoodExhaustion(source.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent + this.getCombatTracker().recordDamage(source, var8); this.setHealth(this.getHealth() - var8); if (var8 < 3.4028235E37F) { -@@ -774,6 +_,7 @@ +@@ -759,6 +_,7 @@ this.gameEvent(GameEvent.ENTITY_DAMAGE); } } @@ -198,7 +198,7 @@ } public boolean isTextFilteringEnabled() { -@@ -860,14 +_,16 @@ +@@ -852,14 +_,16 @@ } @Override @@ -218,71 +218,71 @@ } @Override -@@ -946,15 +_,25 @@ +@@ -938,15 +_,25 @@ } - public void attack(Entity target) { -- if (!this.cannotAttack(target)) { + public void attack(final Entity entity) { +- if (!this.cannotAttack(entity)) { + // Paper start - PlayerAttackEntityEvent -+ boolean willAttack = !this.cannotAttack(target); // Vanilla logic ++ boolean willAttack = !this.cannotAttack(entity); // Vanilla logic + io.papermc.paper.event.player.PrePlayerAttackEntityEvent playerAttackEntityEvent = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent( + (org.bukkit.entity.Player) this.getBukkitEntity(), -+ target.getBukkitEntity(), ++ entity.getBukkitEntity(), + willAttack + ); + + if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable. + // Paper end - PlayerAttackEntityEvent - float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); - ItemStack weaponItem = this.getWeaponItem(); -- DamageSource damageSource = this.createAttackSource(weaponItem); -+ DamageSource damageSource = this.createAttackSource(weaponItem); final DamageSource dmgSourceFinal = damageSource; // Paper - damage events + float baseDamage = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE); + ItemStack attackingItemStack = this.getWeaponItem(); +- DamageSource damageSource = this.createAttackSource(attackingItemStack); ++ DamageSource damageSource = this.createAttackSource(attackingItemStack); final DamageSource dmgSourceFinal = damageSource; // Paper - damage events float attackStrengthScale = this.getAttackStrengthScale(0.5F); - float f1 = attackStrengthScale * (this.getEnchantedDamage(target, f, damageSource) - f); - f *= this.baseDamageScaleFactor(); + float magicBoost = attackStrengthScale * (this.getEnchantedDamage(entity, baseDamage, damageSource) - baseDamage); + baseDamage *= this.baseDamageScaleFactor(); this.onAttack(); -- if (!this.deflectProjectile(target)) { -+ final float dmgFinal = f1; // Paper - damage events -+ if (!this.deflectProjectile(target, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(target, dmgSourceFinal, dmgFinal, false))) { - if (f > 0.0F || f1 > 0.0F) { - boolean flag = attackStrengthScale > 0.9F; - boolean flag1; -@@ -967,7 +_,9 @@ - - f += weaponItem.getItem().getAttackDamageBonus(target, f, damageSource); - boolean flag2 = flag && this.canCriticalAttack(target); -+ flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits - if (flag2) { +- if (!this.deflectProjectile(entity)) { ++ final float dmgFinal = magicBoost; // Paper - damage events ++ if (!this.deflectProjectile(entity, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(entity, dmgSourceFinal, dmgFinal, false))) { + if (baseDamage > 0.0F || magicBoost > 0.0F) { + boolean fullStrengthAttack = attackStrengthScale > 0.9F; + boolean knockbackAttack; +@@ -959,7 +_,9 @@ + + baseDamage += attackingItemStack.getItem().getAttackDamageBonus(entity, baseDamage, damageSource); + boolean criticalAttack = fullStrengthAttack && this.canCriticalAttack(entity); ++ criticalAttack = criticalAttack && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits + if (criticalAttack) { + damageSource = damageSource.critical(); // Paper - critical damage API - f *= 1.5F; + baseDamage *= 1.5F; } -@@ -990,7 +_,7 @@ - this.setLastHurtMob(target); - this.itemAttackInteraction(target, weaponItem, damageSource, true); - this.damageStatsAndHearts(target, f3); +@@ -982,7 +_,7 @@ + this.setLastHurtMob(entity); + this.itemAttackInteraction(entity, attackingItemStack, damageSource, true); + this.damageStatsAndHearts(entity, oldLivingEntityHealth); - this.causeFoodExhaustion(0.1F); + this.causeFoodExhaustion(this.level().spigotConfig.combatExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value } else { this.playServerSideSound(SoundEvents.PLAYER_ATTACK_NODAMAGE); } -@@ -1002,7 +_,7 @@ +@@ -994,7 +_,7 @@ } - private void playServerSideSound(SoundEvent sound) { + private void playServerSideSound(final SoundEvent sound) { - this.level().playSound(null, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), 1.0F, 1.0F); + sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility } - private DamageSource createAttackSource(ItemStack stack) { -@@ -1013,11 +_,12 @@ - return !target.isAttackable() || target.skipAttackInteraction(this); + private DamageSource createAttackSource(final ItemStack attackingItemStack) { +@@ -1005,11 +_,12 @@ + return !entity.isAttackable() || entity.skipAttackInteraction(this); } -- private boolean deflectProjectile(Entity target) { -+ private boolean deflectProjectile(Entity target, java.util.function.BooleanSupplier callEvent) { // Paper - damage events - if (target.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) - && target instanceof Projectile projectile +- private boolean deflectProjectile(final Entity entity) { ++ private boolean deflectProjectile(final Entity entity, final java.util.function.BooleanSupplier callEvent) { // Paper - damage events + if (entity.is(EntityTypeTags.REDIRECTABLE_PROJECTILE) + && entity instanceof Projectile projectile + && callEvent.getAsBoolean() // Paper - damage events && projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, EntityReference.of(this), true)) { - this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource()); @@ -290,16 +290,19 @@ return true; } else { return false; -@@ -1110,21 +_,43 @@ - public void causeExtraKnockback(Entity target, float strength, Vec3 currentMovement) { - if (strength > 0.0F) { - if (target instanceof LivingEntity livingEntity) { -- livingEntity.knockback(strength, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0))); -+ livingEntity.knockback(strength, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - knockback events +@@ -1110,24 +_,45 @@ + if (knockbackAmount > 0.0F) { + if (entity instanceof LivingEntity livingTarget) { + livingTarget.knockback( +- knockbackAmount, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) ++ knockbackAmount, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // Paper - knockback events + ); } else { - target.push( - -Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)) * strength, 0.1, Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) * strength -+ , this // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + entity.push( + -Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)) * knockbackAmount, + 0.1, +- Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) * knockbackAmount ++ Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) * knockbackAmount, this // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent ); } @@ -311,11 +314,11 @@ + // Paper end - Configurable sprint interruption on attack } - if (target instanceof ServerPlayer && target.hurtMarked) { + if (entity instanceof ServerPlayer && entity.hurtMarked) { + // CraftBukkit start - Add Velocity Event + boolean cancelled = false; -+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) target.getBukkitEntity(); -+ org.bukkit.util.Vector velocity = org.bukkit.craftbukkit.util.CraftVector.toBukkit(currentMovement); ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) entity.getBukkitEntity(); ++ org.bukkit.util.Vector velocity = org.bukkit.craftbukkit.util.CraftVector.toBukkit(oldMovement); + + org.bukkit.event.player.PlayerVelocityEvent event = new org.bukkit.event.player.PlayerVelocityEvent(player, velocity.clone()); + this.level().getCraftServer().getPluginManager().callEvent(event); @@ -327,32 +330,32 @@ + } + + if (!cancelled) { - ((ServerPlayer)target).connection.send(new ClientboundSetEntityMotionPacket(target)); - target.hurtMarked = false; - target.setDeltaMovement(currentMovement); + ((ServerPlayer)entity).connection.send(new ClientboundSetEntityMotionPacket(entity)); + entity.hurtMarked = false; + entity.setDeltaMovement(oldMovement); + } + // CraftBukkit end } } -@@ -1145,8 +_,11 @@ - && !(livingEntity instanceof ArmorStand armorStand && armorStand.isMarker()) - && this.distanceToSqr(livingEntity) < 9.0) { - float f1 = this.getEnchantedDamage(livingEntity, var12, damageSource) * strengthScale; -- if (livingEntity.hurtServer(serverLevel, damageSource, f1)) { -- livingEntity.knockback(0.4F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0))); +@@ -1148,8 +_,11 @@ + && !(nearby instanceof ArmorStand armorStand && armorStand.isMarker()) + && this.distanceToSqr(nearby) < 9.0) { + float enchantedDamage = this.getEnchantedDamage(nearby, var12, damageSource) * attackStrengthScale; +- if (nearby.hurtServer(serverLevel, damageSource, enchantedDamage)) { +- nearby.knockback(0.4F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0))); + // Paper start - Only apply knockback if the event is not canceled -+ livingEntity.lastDamageCancelled = false; -+ if (livingEntity.hurtServer(serverLevel, damageSource.knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK), f1) && !livingEntity.lastDamageCancelled) { ++ nearby.lastDamageCancelled = false; ++ if (nearby.hurtServer(serverLevel, damageSource.knownCause(org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK), enchantedDamage) && !nearby.lastDamageCancelled) { + // Paper end - Only apply knockback if the event is not canceled -+ livingEntity.knockback(0.4F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // Paper - knockback events - EnchantmentHelper.doPostAttackEffects(serverLevel, livingEntity, damageSource); ++ nearby.knockback(0.4F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // Paper - knockback events + EnchantmentHelper.doPostAttackEffects(serverLevel, nearby, damageSource); } } -@@ -1177,7 +_,16 @@ - - @Override - public boolean stabAttack(EquipmentSlot slot, Entity target, float damageAmount, boolean damage, boolean knockback, boolean dismount) { +@@ -1182,7 +_,16 @@ + public boolean stabAttack( + final EquipmentSlot slot, final Entity target, float baseDamage, final boolean dealsDamage, final boolean dealsKnockback, final boolean dismounts + ) { - if (this.cannotAttack(target)) { + // Paper start - PlayerAttackEntityEvent + boolean cannotAttack = this.cannotAttack(target); // Vanilla logic @@ -366,67 +369,66 @@ + // Paper end - PlayerAttackEntityEvent return false; } else { - ItemStack itemBySlot = this.getItemBySlot(slot); -@@ -1188,7 +_,8 @@ - damageAmount *= this.baseDamageScaleFactor(); + ItemStack weaponItem = this.getItemBySlot(slot); +@@ -1193,7 +_,8 @@ + baseDamage *= this.baseDamageScaleFactor(); } -- if (knockback && this.deflectProjectile(target)) { -+ final float dmgFinal = f; // Paper - damage events -+ if (knockback && this.deflectProjectile(target, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(target, damageSource, dmgFinal, false))) { // Paper - damage events +- if (dealsKnockback && this.deflectProjectile(target)) { ++ final float dmgFinal = magicBoost; // Paper - damage events ++ if (dealsKnockback && this.deflectProjectile(target, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(target, damageSource, dmgFinal, false))) { // Paper - damage events return true; } else { - float f1 = damage ? damageAmount + f : 0.0F; -@@ -1216,7 +_,7 @@ + float totalDamage = dealsDamage ? baseDamage + magicBoost : 0.0F; +@@ -1221,7 +_,7 @@ this.setLastHurtMob(target); - this.itemAttackInteraction(target, itemBySlot, damageSource, flag); - this.damageStatsAndHearts(target, f2); + this.itemAttackInteraction(target, weaponItem, damageSource, wasHurt); + this.damageStatsAndHearts(target, oldLivingEntityHealth); - this.causeFoodExhaustion(0.1F); + this.causeFoodExhaustion(this.level().spigotConfig.combatExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value return true; } } -@@ -1227,8 +_,8 @@ +@@ -1232,8 +_,8 @@ } @Override -- public void remove(Entity.RemovalReason reason) { +- public void remove(final Entity.RemovalReason reason) { - super.remove(reason); -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause + super.remove(reason, eventCause); // CraftBukkit - add Bukkit remove cause this.inventoryMenu.removed(this); if (this.hasContainerOpen()) { this.doCloseContainer(); -@@ -1296,6 +_,12 @@ +@@ -1301,6 +_,12 @@ } - public Either startSleepInBed(BlockPos bedPos) { + public Either startSleepInBed(final BlockPos pos) { + // CraftBukkit start -+ return this.startSleepInBed(bedPos, false); ++ return this.startSleepInBed(pos, false); + } + -+ public Either startSleepInBed(BlockPos bedPos, boolean force) { ++ public Either startSleepInBed(final BlockPos pos, final boolean force) { + // CraftBukkit end - this.startSleeping(bedPos); + this.startSleeping(pos); this.sleepCounter = 0; return Either.right(Unit.INSTANCE); -@@ -1407,7 +_,7 @@ +@@ -1417,7 +_,7 @@ @Override - public boolean causeFallDamage(double fallDistance, float damageMultiplier, DamageSource damageSource) { + public boolean causeFallDamage(final double fallDistance, final float damageModifier, final DamageSource damageSource) { - if (this.abilities.mayfly) { + if (this.abilities.mayfly && !this.flyingFallDamage.toBooleanOrElse(false)) { // Paper - flying fall damage return false; } else { if (fallDistance >= 2.0) { -@@ -1448,7 +_,15 @@ +@@ -1438,7 +_,15 @@ } public void startFallFlying() { -- this.setSharedFlag(Entity.FLAG_FALL_FLYING, true); + // CraftBukkit start + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callToggleGlideEvent(this, true).isCancelled()) { -+ this.setSharedFlag(Entity.FLAG_FALL_FLYING, true); + this.setSharedFlag(Entity.FLAG_FALL_FLYING, true); + } else { + // SPIGOT-5542: must toggle like below + this.setSharedFlag(Entity.FLAG_FALL_FLYING, true); @@ -436,16 +438,16 @@ } @Override -@@ -1546,7 +_,7 @@ +@@ -1536,7 +_,7 @@ - if (levels > 0 && this.experienceLevel % 5 == 0 && this.lastLevelUpTime < this.tickCount - 100.0F) { - float f = this.experienceLevel > 30 ? 1.0F : this.experienceLevel / 30.0F; -- this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), f * 0.75F, 1.0F); -+ Player.sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), f * 0.75F, 1.0F); // Paper - send while respecting visibility + if (amount > 0 && this.experienceLevel % 5 == 0 && this.lastLevelUpTime < this.tickCount - 100.0F) { + float vol = this.experienceLevel > 30 ? 1.0F : this.experienceLevel / 30.0F; +- this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), vol * 0.75F, 1.0F); ++ Player.sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_LEVELUP, this.getSoundSource(), vol * 0.75F, 1.0F); // Paper - send while respecting visibility this.lastLevelUpTime = this.tickCount; } } -@@ -1554,15 +_,35 @@ +@@ -1544,15 +_,35 @@ public int getXpNeededForNextLevel() { if (this.experienceLevel >= 30) { return 112 + (this.experienceLevel - 30) * 9; @@ -464,18 +466,18 @@ + } + // Paper end - send while respecting visibility + - public void causeFoodExhaustion(float exhaustion) { + public void causeFoodExhaustion(final float amount) { + // CraftBukkit start -+ this.causeFoodExhaustion(exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.UNKNOWN); ++ this.causeFoodExhaustion(amount, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.UNKNOWN); + } + -+ public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { ++ public void causeFoodExhaustion(final float amount, final org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) { + // CraftBukkit end if (!this.abilities.invulnerable) { if (!this.level().isClientSide()) { -- this.foodData.addExhaustion(exhaustion); +- this.foodData.addExhaustion(amount); + // CraftBukkit start -+ org.bukkit.event.entity.EntityExhaustionEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerExhaustionEvent(this, reason, exhaustion); ++ org.bukkit.event.entity.EntityExhaustionEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerExhaustionEvent(this, reason, amount); + if (!event.isCancelled()) { + this.foodData.addExhaustion(event.getExhaustion()); + } @@ -483,7 +485,7 @@ } } } -@@ -1821,10 +_,31 @@ +@@ -1814,10 +_,31 @@ @Override public void onAttack() { @@ -516,7 +518,7 @@ public void resetOnlyAttackStrengthTicker() { this.attackStrengthTicker = 0; } -@@ -1856,17 +_,32 @@ +@@ -1849,17 +_,32 @@ return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING); } @@ -535,23 +537,23 @@ + // Paper end - PlayerReadyArrowEvent + @Override - public ItemStack getProjectile(ItemStack shootable) { - if (!(shootable.getItem() instanceof ProjectileWeaponItem)) { + public ItemStack getProjectile(final ItemStack heldWeapon) { + if (!(heldWeapon.getItem() instanceof ProjectileWeaponItem)) { return ItemStack.EMPTY; } else { -- Predicate supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles(); +- Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles(); + final org.apache.commons.lang3.mutable.MutableBoolean anyEventCancelled = new org.apache.commons.lang3.mutable.MutableBoolean(); // Paper - PlayerReadyArrowEvent -+ Predicate supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent - ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles); ++ Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent + ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedProjectiles); if (!heldProjectile.isEmpty()) { return heldProjectile; } else { -- supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles(); -+ supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(shootable, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent +- supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles(); ++ supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent for (int i = 0; i < this.inventory.getContainerSize(); i++) { - ItemStack item = this.inventory.getItem(i); -@@ -1875,6 +_,7 @@ + ItemStack itemStack = this.inventory.getItem(i); +@@ -1868,6 +_,7 @@ } } @@ -559,7 +561,7 @@ return this.hasInfiniteMaterials() ? new ItemStack(Items.ARROW) : ItemStack.EMPTY; } } -@@ -2055,5 +_,6 @@ +@@ -2031,5 +_,6 @@ public static final Player.BedSleepingProblem OBSTRUCTED = new Player.BedSleepingProblem(Component.translatable("block.minecraft.bed.obstructed")); public static final Player.BedSleepingProblem OTHER_PROBLEM = new Player.BedSleepingProblem(null); public static final Player.BedSleepingProblem NOT_SAFE = new Player.BedSleepingProblem(Component.translatable("block.minecraft.bed.not_safe")); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/ProfilePublicKey.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/ProfilePublicKey.java.patch index 1290b7263d12..88d2fdbc6020 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/ProfilePublicKey.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/ProfilePublicKey.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/entity/player/ProfilePublicKey.java @@ -24,7 +_,7 @@ - public static ProfilePublicKey createValidated(SignatureValidator signatureValidator, UUID profileId, ProfilePublicKey.Data data) throws ProfilePublicKey.ValidationException { - if (!data.validateSignature(signatureValidator, profileId)) { + public static ProfilePublicKey createValidated(final SignatureValidator validator, final UUID profileId, final ProfilePublicKey.Data data) throws ProfilePublicKey.ValidationException { + if (!data.validateSignature(validator, profileId)) { - throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE); + throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE, org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PUBLIC_KEY_SIGNATURE); // Paper - kick event causes } else { @@ -16,7 +16,7 @@ + public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; // Paper + + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - public ValidationException(Component component) { + public ValidationException(final Component component) { + // Paper start + this(component, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch index 81c63120251b..5acc11bd3d40 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EvokerFangs.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/projectile/EvokerFangs.java +++ b/net/minecraft/world/entity/projectile/EvokerFangs.java -@@ -96,7 +_,7 @@ +@@ -98,7 +_,7 @@ } if (--this.lifeTicks < 0) { @@ -9,12 +9,12 @@ } } } -@@ -105,7 +_,7 @@ - LivingEntity owner = this.getOwner(); - if (target.isAlive() && !target.isInvulnerable() && target != owner) { - if (owner == null) { -- target.hurt(this.damageSources().magic(), 6.0F); -+ target.hurt(this.damageSources().magic().eventEntityDamager(this), 6.0F); // CraftBukkit +@@ -107,7 +_,7 @@ + LivingEntity currentOwner = this.getOwner(); + if (entity.isAlive() && !entity.isInvulnerable() && entity != currentOwner) { + if (currentOwner == null) { +- entity.hurt(this.damageSources().magic(), 6.0F); ++ entity.hurt(this.damageSources().magic().eventEntityDamager(this), 6.0F); // CraftBukkit } else { - if (owner.isAlliedTo(target)) { + if (currentOwner.isAlliedTo(entity)) { return; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch index 060c0ec1b92e..0c9a562f8db8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch @@ -3,24 +3,24 @@ @@ -72,6 +_,12 @@ } - public void signalTo(Vec3 pos) { -+ // Paper start - Change EnderEye target without changing other things -+ this.signalTo(pos, true); + public void signalTo(final Vec3 target) { ++ // Paper start - Change EyeOfEnder target without changing other things ++ this.signalTo(target, true); + } + -+ public void signalTo(Vec3 pos, boolean update) { -+ // Paper end - Change EnderEye target without changing other things - Vec3 vec3 = pos.subtract(this.position()); - double d = vec3.horizontalDistance(); - if (d > 12.0) { ++ public void signalTo(final Vec3 target, final boolean update) { ++ // Paper end - Change EyeOfEnder target without changing other things + Vec3 delta = target.subtract(this.position()); + double horizontalDistance = delta.horizontalDistance(); + if (horizontalDistance > 12.0) { @@ -80,8 +_,10 @@ - this.target = pos; + this.target = target; } -+ if (update) { // Paper - Change EnderEye target without changing other things ++ if (update) { // Paper - Change EyeOfEnder target without changing other things this.life = 0; this.surviveAfterDeath = this.random.nextInt(5) > 0; -+ } // Paper - Change EnderEye target without changing other things ++ } // Paper - Change EyeOfEnder target without changing other things } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch index 15e4b962ee8e..99599a64ff97 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch @@ -6,25 +6,25 @@ public @Nullable LivingEntity attachedToEntity; + public java.util.@Nullable UUID spawningEntity; // Paper - public FireworkRocketEntity(EntityType type, Level level) { + public FireworkRocketEntity(final EntityType type, final Level level) { super(type, level); @@ -163,7 +_,7 @@ } - if (!this.noPhysics && this.isAlive() && hitResultOnMoveVector.getType() != HitResult.Type.MISS) { -- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); -+ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + if (!this.noPhysics && this.isAlive() && hitResult.getType() != HitResult.Type.MISS) { +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event this.needsSync = true; } @@ -187,7 +_,11 @@ } - if (this.life > this.lifetime && this.level() instanceof ServerLevel serverLevel) { -- this.explode(serverLevel); + if (this.life > this.lifetime && this.level() instanceof ServerLevel level) { +- this.explode(level); + // Paper start - Call FireworkExplodeEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) { -+ this.explode(serverLevel); ++ this.explode(level); + } + // Paper end - Call FireworkExplodeEvent } @@ -39,31 +39,31 @@ } @Override - protected void onHitEntity(EntityHitResult result) { - super.onHitEntity(result); - if (this.level() instanceof ServerLevel serverLevel) { -- this.explode(serverLevel); + protected void onHitEntity(final EntityHitResult hitResult) { + super.onHitEntity(hitResult); + if (this.level() instanceof ServerLevel level) { +- this.explode(level); + // Paper start - Call FireworkExplodeEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) { -+ this.explode(serverLevel); ++ this.explode(level); + } + // Paper end - Call FireworkExplodeEvent } } @@ -211,7 +_,11 @@ - BlockPos blockPos = new BlockPos(result.getBlockPos()); - this.level().getBlockState(blockPos).entityInside(this.level(), blockPos, this, InsideBlockEffectApplier.NOOP, true); - if (this.level() instanceof ServerLevel serverLevel && this.hasExplosion()) { -- this.explode(serverLevel); + BlockPos pos = new BlockPos(hitResult.getBlockPos()); + this.level().getBlockState(pos).entityInside(this.level(), pos, this, InsideBlockEffectApplier.NOOP, true); + if (this.level() instanceof ServerLevel level && this.hasExplosion()) { +- this.explode(level); + // Paper start - Call FireworkExplodeEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this)) { -+ this.explode(serverLevel); ++ this.explode(level); + } + // Paper end - Call FireworkExplodeEvent } - super.onHitBlock(result); + super.onHitBlock(hitResult); @@ -283,6 +_,7 @@ output.putInt("LifeTime", this.lifetime); output.store("FireworksItem", ItemStack.CODEC, this.getItem()); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch index ebdb125b7d61..9632b2c537da 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch @@ -16,7 +16,7 @@ + public boolean skyInfluenced = true; + // CraftBukkit end + - private FishingHook(EntityType type, Level level, int luck, int lureSpeed) { + private FishingHook(final EntityType type, final Level level, final int luck, final int lureSpeed) { super(type, level); this.luck = Math.max(0, luck); this.lureSpeed = Math.max(0, lureSpeed); @@ -26,14 +26,14 @@ + // Paper end - Configurable fishing time ranges } - public FishingHook(EntityType type, Level level) { + public FishingHook(final EntityType type, final Level level) { @@ -152,12 +_,12 @@ super.tick(); - Player playerOwner = this.getPlayerOwner(); - if (playerOwner == null) { + Player owner = this.getPlayerOwner(); + if (owner == null) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else if (this.level().isClientSide() || !this.shouldStopFishing(playerOwner)) { + } else if (this.level().isClientSide() || !this.shouldStopFishing(owner)) { if (this.onGround()) { this.life++; if (this.life >= 1200) { @@ -51,7 +51,7 @@ return; } - if (flag) { + if (isInWater) { this.setDeltaMovement(this.getDeltaMovement().multiply(0.3, 0.2, 0.3)); + new io.papermc.paper.event.entity.FishHookStateChangeEvent((org.bukkit.entity.FishHook) getBukkitEntity(), org.bukkit.entity.FishHook.HookState.BOBBING).callEvent(); // Paper - Add FishHookStateChangeEvent. #BOBBING this.currentState = FishingHook.FishHookState.BOBBING; @@ -75,24 +75,24 @@ } private void checkCollision() { - HitResult hitResultOnMoveVector = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); -- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); -+ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); } @Override @@ -298,11 +_,11 @@ ServerLevel serverLevel = (ServerLevel)this.level(); - int i = 1; - BlockPos blockPos = pos.above(); -- if (this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockPos)) { -+ if (this.rainInfluenced && this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockPos)) { // CraftBukkit - i++; + int fishingSpeed = 1; + BlockPos above = blockPos.above(); +- if (this.random.nextFloat() < 0.25F && this.level().isRainingAt(above)) { ++ if (this.rainInfluenced && this.random.nextFloat() < 0.25F && this.level().isRainingAt(above)) { // CraftBukkit + fishingSpeed++; } -- if (this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockPos)) { -+ if (this.skyInfluenced && this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockPos)) { // CraftBukkit - i--; +- if (this.random.nextFloat() < 0.5F && !this.level().canSeeSky(above)) { ++ if (this.skyInfluenced && this.random.nextFloat() < 0.5F && !this.level().canSeeSky(above)) { // CraftBukkit + fishingSpeed--; } @@ -312,6 +_,10 @@ @@ -105,9 +105,9 @@ + // CraftBukkit end } } else if (this.timeUntilHooked > 0) { - this.timeUntilHooked -= i; + this.timeUntilHooked -= fishingSpeed; @@ -335,6 +_,12 @@ - serverLevel.sendParticles(ParticleTypes.FISHING, d, d1, d2, 0, -f2, 0.01, f1, 1.0); + serverLevel.sendParticles(ParticleTypes.FISHING, fishX, fishY, fishZ, 0, -particleZMovement, 0.01, particleXMovement, 1.0); } } else { + // CraftBukkit start @@ -117,9 +117,9 @@ + } + // CraftBukkit end this.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); - double d3 = this.getY() + 0.5; + double y = this.getY() + 0.5; serverLevel.sendParticles( -@@ -386,14 +_,31 @@ +@@ -378,14 +_,31 @@ } if (this.timeUntilLured <= 0) { @@ -153,89 +153,84 @@ + } + // Paper end - more projectile api - extract time until lured reset logic - public boolean calculateOpenWater(BlockPos pos) { - FishingHook.OpenWaterType openWaterType = FishingHook.OpenWaterType.INVALID; -@@ -452,15 +_,31 @@ - protected void readAdditionalSaveData(ValueInput input) { + public boolean calculateOpenWater(final BlockPos blockPos) { + FishingHook.OpenWaterType previousLayer = FishingHook.OpenWaterType.INVALID; +@@ -444,15 +_,30 @@ + protected void readAdditionalSaveData(final ValueInput input) { } -+ + // Paper start - Add hand parameter to PlayerFishEvent + @Deprecated @io.papermc.paper.annotation.DoNotUse - public int retrieve(ItemStack stack) { -+ return this.retrieve(stack, net.minecraft.world.InteractionHand.MAIN_HAND); + public int retrieve(final ItemStack rod) { ++ return this.retrieve(rod, net.minecraft.world.InteractionHand.MAIN_HAND); + } + -+ public int retrieve(ItemStack stack, net.minecraft.world.InteractionHand hand) { ++ public int retrieve(final ItemStack rod, final net.minecraft.world.InteractionHand hand) { + // Paper end - Add hand parameter to PlayerFishEvent - Player playerOwner = this.getPlayerOwner(); - if (!this.level().isClientSide() && playerOwner != null && !this.shouldStopFishing(playerOwner)) { - int i = 0; + Player owner = this.getPlayerOwner(); + if (!this.level().isClientSide() && owner != null && !this.shouldStopFishing(owner)) { + int dmg = 0; if (this.hookedIn != null) { + // CraftBukkit start -+ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) owner.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_ENTITY); // Paper - Add hand parameter to PlayerFishEvent + if (!playerFishEvent.callEvent()) { + return 0; + } + if (this.hookedIn != null) { // Paper - re-check to see if there is a hooked entity + // CraftBukkit end this.pullEntity(this.hookedIn); - CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)playerOwner, stack, this, Collections.emptyList()); + CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)owner, rod, this, Collections.emptyList()); this.level().broadcastEntityEvent(this, EntityEvent.FISHING_ROD_REEL_IN); - i = this.hookedIn instanceof ItemEntity ? 3 : 5; + dmg = this.hookedIn instanceof ItemEntity ? 3 : 5; + } // Paper - re-check to see if there is a hooked entity } else if (this.nibble > 0) { - LootParams lootParams = new LootParams.Builder((ServerLevel)this.level()) + LootParams params = new LootParams.Builder((ServerLevel)this.level()) .withParameter(LootContextParams.ORIGIN, this.position()) -@@ -474,18 +_,27 @@ +@@ -466,14 +_,27 @@ - for (ItemStack itemStack : randomItems) { - ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); + for (ItemStack itemStack : items) { + ItemEntity entity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); + // CraftBukkit start -+ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), itemEntity.getBukkitEntity(), (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_FISH); // Paper - itemEntity may be null // Paper - Add hand parameter to PlayerFishEvent ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) owner.getBukkitEntity(), entity.getBukkitEntity(), (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.CAUGHT_FISH); // Paper - itemEntity may be null // Paper - Add hand parameter to PlayerFishEvent + playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); + if (!playerFishEvent.callEvent()) { + return 0; + } + // CraftBukkit end - double d = playerOwner.getX() - this.getX(); - double d1 = playerOwner.getY() - this.getY(); - double d2 = playerOwner.getZ() - this.getZ(); - double d3 = 0.1; - itemEntity.setDeltaMovement(d * 0.1, d1 * 0.1 + Math.sqrt(Math.sqrt(d * d + d1 * d1 + d2 * d2)) * 0.08, d2 * 0.1); - this.level().addFreshEntity(itemEntity); -- playerOwner.level() -- .addFreshEntity( -- new ExperienceOrb( -- playerOwner.level(), playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5, this.random.nextInt(6) + 1 -- ) -- ); + double xa = owner.getX() - this.getX(); + double ya = owner.getY() - this.getY(); + double za = owner.getZ() - this.getZ(); + double speed = 0.1; + entity.setDeltaMovement(xa * 0.1, ya * 0.1 + Math.sqrt(Math.sqrt(xa * xa + ya * ya + za * za)) * 0.08, za * 0.1); + this.level().addFreshEntity(entity); +- owner.level() +- .addFreshEntity(new ExperienceOrb(owner.level(), owner.getX(), owner.getY() + 0.5, owner.getZ() + 0.5, this.random.nextInt(6) + 1)); + if (playerFishEvent.getExpToDrop() > 0) { // CraftBukkit - custom exp -+ playerOwner.level() ++ owner.level() + .addFreshEntity( + new ExperienceOrb( -+ playerOwner.level(), new net.minecraft.world.phys.Vec3(playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5), net.minecraft.world.phys.Vec3.ZERO, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this // Paper ++ owner.level(), new net.minecraft.world.phys.Vec3(owner.getX(), owner.getY() + 0.5, owner.getZ() + 0.5), net.minecraft.world.phys.Vec3.ZERO, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this // Paper + ) + ); + } if (itemStack.is(ItemTags.FISHES)) { - playerOwner.awardStat(Stats.FISH_CAUGHT, 1); + owner.awardStat(Stats.FISH_CAUGHT, 1); } -@@ -495,10 +_,24 @@ +@@ -483,10 +_,24 @@ } if (this.onGround()) { + // CraftBukkit start -+ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) owner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.IN_GROUND); // Paper - Add hand parameter to PlayerFishEvent + if (!playerFishEvent.callEvent()) { + return 0; + } + // CraftBukkit end - i = 2; + dmg = 2; } + // CraftBukkit start -+ if (i == 0) { -+ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) playerOwner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent ++ if (dmg == 0) { ++ org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) owner.getBukkitEntity(), null, (org.bukkit.entity.FishHook) this.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.REEL_IN); // Paper - Add hand parameter to PlayerFishEvent + if (!playerFishEvent.callEvent()) { + return 0; + } @@ -244,25 +239,25 @@ - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - return i; + return dmg; } else { return 0; -@@ -528,9 +_,9 @@ +@@ -516,9 +_,9 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, final org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause this.updateOwnerInfo(null); - super.remove(reason); + super.remove(reason, cause); // CraftBukkit - add Bukkit remove cause } @Override -@@ -576,7 +_,7 @@ +@@ -564,7 +_,7 @@ if (this.getPlayerOwner() == null) { - int data = packet.getData(); - LOGGER.error("Failed to recreate fishing hook on client. {} (id: {}) is not a valid owner.", this.level().getEntity(data), data); + int ownerId = packet.getData(); + LOGGER.error("Failed to recreate fishing hook on client. {} (id: {}) is not a valid owner.", this.level().getEntity(ownerId), ownerId); - this.discard(); + this.discard(null); // CraftBukkit - add Bukkit remove cause } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch index 81a54ac237bf..311ea6aa01f7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/LlamaSpit.java.patch @@ -2,15 +2,15 @@ +++ b/net/minecraft/world/entity/projectile/LlamaSpit.java @@ -43,16 +_,16 @@ super.tick(); - Vec3 deltaMovement = this.getDeltaMovement(); - HitResult hitResultOnMoveVector = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); -- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); -+ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event - double d = this.getX() + deltaMovement.x; - double d1 = this.getY() + deltaMovement.y; - double d2 = this.getZ() + deltaMovement.z; + Vec3 movement = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event + double x = this.getX() + movement.x; + double y = this.getY() + movement.y; + double z = this.getZ() + movement.z; this.updateRotation(); - float f = 0.99F; + float inertia = 0.99F; if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause @@ -18,11 +18,11 @@ - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else { - this.setDeltaMovement(deltaMovement.scale(0.99F)); + this.setDeltaMovement(movement.scale(0.99F)); this.applyGravity(); @@ -76,7 +_,7 @@ - protected void onHitBlock(BlockHitResult result) { - super.onHitBlock(result); + protected void onHitBlock(final BlockHitResult hitResult) { + super.onHitBlock(hitResult); if (!this.level().isClientSide()) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch index bbddee96ba82..ddc9208b6e31 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -6,16 +6,16 @@ private @Nullable Entity lastDeflectedBy; + protected boolean hitCancelled = false; // CraftBukkit - protected Projectile(EntityType type, Level level) { + protected Projectile(final EntityType type, final Level level) { super(type, level); @@ -51,12 +_,25 @@ - protected void setOwner(@Nullable EntityReference owner) { + protected void setOwner(final @Nullable EntityReference owner) { this.owner = owner; + this.refreshProjectileSource(false); // Paper } - public void setOwner(@Nullable Entity owner) { + public void setOwner(final @Nullable Entity owner) { this.setOwner(EntityReference.of(owner)); } @@ -36,72 +36,90 @@ return EntityReference.getEntity(this.owner, this.level()); @@ -83,6 +_,7 @@ @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { this.setOwner(EntityReference.read(input, "Owner")); + if (this instanceof net.minecraft.world.entity.projectile.throwableitemprojectile.ThrownEnderpearl && this.level().paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && this.level().paperConfig().misc.legacyEnderPearlBehavior) { this.owner = null; } // Paper - Reset pearls when they stop being ticked; Don't store shooter name for pearls to block enderpearl travel exploit this.leftOwner = input.getBooleanOr("LeftOwner", false); this.hasBeenShot = input.getBooleanOr("HasBeenShot", false); } @@ -155,7 +_,14 @@ - float f2 = Mth.cos(y * (float) (Math.PI / 180.0)) * Mth.cos(x * (float) (Math.PI / 180.0)); - this.shoot(f, f1, f2, velocity, inaccuracy); - Vec3 knownMovement = shooter.getKnownMovement(); + float zd = Mth.cos(yRot * (float) (Math.PI / 180.0)) * Mth.cos(xRot * (float) (Math.PI / 180.0)); + this.shoot(xd, yd, zd, pow, uncertainty); + Vec3 sourceMovement = source.getKnownMovement(); + // Paper start - allow disabling relative velocity -+ if (Double.isNaN(knownMovement.x) || Double.isNaN(knownMovement.y) || Double.isNaN(knownMovement.z)) { -+ knownMovement = new Vec3(0, 0, 0); ++ if (Double.isNaN(sourceMovement.x) || Double.isNaN(sourceMovement.y) || Double.isNaN(sourceMovement.z)) { ++ sourceMovement = new Vec3(0, 0, 0); + } -+ if (!shooter.level().paperConfig().misc.disableRelativeProjectileVelocity) { - this.setDeltaMovement(this.getDeltaMovement().add(knownMovement.x, shooter.onGround() ? 0.0 : knownMovement.y, knownMovement.z)); ++ if (!source.level().paperConfig().misc.disableRelativeProjectileVelocity) { + this.setDeltaMovement(this.getDeltaMovement().add(sourceMovement.x, source.onGround() ? 0.0 : sourceMovement.y, sourceMovement.z)); + } + // Paper end - allow disabling relative velocity } @Override -@@ -175,7 +_,12 @@ - public static T spawnProjectileFromRotation( - Projectile.ProjectileFactory factory, ServerLevel level, ItemStack spawnedFrom, LivingEntity owner, float z, float velocity, float inaccuracy +@@ -181,7 +_,20 @@ + final float pow, + final float uncertainty ) { - return spawnProjectile( + // Paper start - PlayerLaunchProjectileEvent -+ return spawnProjectileFromRotationDelayed(factory, level, spawnedFrom, owner, z, velocity, inaccuracy).spawn(); ++ return spawnProjectileFromRotationDelayed(creator, serverLevel, itemStack, source, yOffset, pow, uncertainty).spawn(); + } -+ public static Delayed spawnProjectileFromRotationDelayed(Projectile.ProjectileFactory factory, ServerLevel level, ItemStack spawnedFrom, LivingEntity owner, float z, float velocity, float inaccuracy) { ++ public static Delayed spawnProjectileFromRotationDelayed( ++ final Projectile.ProjectileFactory creator, ++ final ServerLevel serverLevel, ++ final ItemStack itemStack, ++ final LivingEntity source, ++ final float yOffset, ++ final float pow, ++ final float uncertainty ++ ) { + return spawnProjectileDelayed( + // Paper end - PlayerLaunchProjectileEvent - factory.create(level, owner, spawnedFrom), - level, - spawnedFrom, -@@ -200,7 +_,13 @@ - public static T spawnProjectileUsingShoot( - T projectile, ServerLevel level, ItemStack spawnedFrom, double x, double y, double z, float velocity, float inaccuracy + creator.create(serverLevel, source, itemStack), + serverLevel, + itemStack, +@@ -215,7 +_,22 @@ + final float pow, + final float uncertainty ) { -- return spawnProjectile(projectile, level, spawnedFrom, projectile1 -> projectile.shoot(x, y, z, velocity, inaccuracy)); +- return spawnProjectile(projectile, serverLevel, itemStack, i -> projectile.shoot(targetX, targetY, targetZ, pow, uncertainty)); + // Paper start - fixes and addition to spawn reason API -+ return spawnProjectileUsingShootDelayed(projectile, level, spawnedFrom, x, y, z, velocity, inaccuracy).spawn(); ++ return spawnProjectileUsingShootDelayed(projectile, serverLevel, itemStack, targetX, targetY, targetZ, pow, uncertainty).spawn(); + } + -+ public static Delayed spawnProjectileUsingShootDelayed(T projectile, ServerLevel level, ItemStack spawnedFrom, double x, double y, double z, float velocity, float inaccuracy) { -+ return spawnProjectileDelayed(projectile, level, spawnedFrom, projectile1 -> projectile.shoot(x, y, z, velocity, inaccuracy)); ++ public static Delayed spawnProjectileUsingShootDelayed( ++ final T projectile, ++ final ServerLevel serverLevel, ++ final ItemStack itemStack, ++ final double targetX, ++ final double targetY, ++ final double targetZ, ++ final float pow, ++ final float uncertainty ++ ) { ++ return spawnProjectileDelayed(projectile, serverLevel, itemStack, i -> projectile.shoot(targetX, targetY, targetZ, pow, uncertainty)); + // Paper end - fixes and addition to spawn reason API } - public static T spawnProjectile(T projectile, ServerLevel level, ItemStack spawnedFrom) { -@@ -208,11 +_,46 @@ - } - - public static T spawnProjectile(T projectile, ServerLevel level, ItemStack stack, Consumer adapter) { + public static T spawnProjectile(final T projectile, final ServerLevel serverLevel, final ItemStack itemStack) { +@@ -225,11 +_,46 @@ + public static T spawnProjectile( + final T projectile, final ServerLevel serverLevel, final ItemStack itemStack, final Consumer shootFunction + ) { +- shootFunction.accept(projectile); +- serverLevel.addFreshEntity(projectile); +- projectile.applyOnProjectileSpawned(serverLevel, itemStack); +- return projectile; +- } + // Paper start - delayed projectile spawning -+ return spawnProjectileDelayed(projectile, level, stack, adapter).spawn(); ++ return spawnProjectileDelayed(projectile, serverLevel, itemStack, shootFunction).spawn(); + } + -+ public static Delayed spawnProjectileDelayed(T projectile, ServerLevel level, ItemStack stack, Consumer adapter) { ++ public static Delayed spawnProjectileDelayed(T projectile, ServerLevel serverLevel, ItemStack itemStack, Consumer adapter) { + // Paper end - delayed projectile spawning - adapter.accept(projectile); -- level.addFreshEntity(projectile); -- projectile.applyOnProjectileSpawned(level, stack); -- return projectile; -- } -+ return new Delayed<>(projectile, level, stack); // Paper - delayed projectile spawning ++ adapter.accept(projectile); ++ return new Delayed<>(projectile, serverLevel, itemStack); // Paper - delayed projectile spawning + } + + // Paper start - delayed projectile spawning @@ -135,9 +153,9 @@ + } + // Paper end - delayed projectile spawning - public void applyOnProjectileSpawned(ServerLevel level, ItemStack spawnedFrom) { - EnchantmentHelper.onProjectileSpawned(level, spawnedFrom, this, item -> {}); -@@ -224,6 +_,17 @@ + public void applyOnProjectileSpawned(final ServerLevel serverLevel, final ItemStack pickupItemStack) { + EnchantmentHelper.onProjectileSpawned(serverLevel, pickupItemStack, this, item -> {}); +@@ -241,6 +_,17 @@ } } @@ -152,20 +170,20 @@ + } + // CraftBukkit end + - protected ProjectileDeflection hitTargetOrDeflectSelf(HitResult hitResult) { + protected ProjectileDeflection hitTargetOrDeflectSelf(final HitResult hitResult) { if (hitResult.getType() == HitResult.Type.ENTITY) { EntityHitResult entityHitResult = (EntityHitResult)hitResult; -@@ -291,15 +_,35 @@ +@@ -313,15 +_,35 @@ } - protected void onHitBlock(BlockHitResult result) { + protected void onHitBlock(final BlockHitResult hitResult) { + // CraftBukkit start - cancellable hit event + if (this.hitCancelled) { + return; + } + // CraftBukkit end - BlockState blockState = this.level().getBlockState(result.getBlockPos()); - blockState.onProjectileHit(this.level(), blockState, result, this); + BlockState state = this.level().getBlockState(hitResult.getBlockPos()); + state.onProjectileHit(this.level(), state, hitResult, this); } + // Paper start @@ -174,35 +192,35 @@ + } + // Paper end + - protected boolean canHitEntity(Entity target) { - if (!target.canBeHitByProjectile()) { + protected boolean canHitEntity(final Entity entity) { + if (!entity.canBeHitByProjectile()) { return false; } else { Entity owner = this.getOwner(); + // Paper start - Cancel hit for vanished entities + if (owner instanceof net.minecraft.server.level.ServerPlayer) { -+ org.bukkit.entity.Entity collided = target.getBukkitEntity(); ++ org.bukkit.entity.Entity collided = entity.getBukkitEntity(); + org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) owner.getBukkitEntity(); + if (!shooter.canSee(collided)) { + return false; + } + } + // Paper end - Cancel hit for vanished entities - return owner == null || this.leftOwner || !owner.isPassengerOfSameVehicle(target); + return owner == null || this.leftOwner || !owner.isPassengerOfSameVehicle(entity); } } -@@ -312,13 +_,7 @@ +@@ -334,13 +_,7 @@ } - protected static float lerpRotation(float currentRotation, float targetRotation) { -- while (targetRotation - currentRotation < -180.0F) { -- currentRotation -= 360.0F; + protected static float lerpRotation(float rotO, final float rot) { +- while (rot - rotO < -180.0F) { +- rotO -= 360.0F; - } - -- while (targetRotation - currentRotation >= 180.0F) { -- currentRotation += 360.0F; +- while (rot - rotO >= 180.0F) { +- rotO += 360.0F; - } -+ currentRotation += Math.round((targetRotation - currentRotation) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server ++ rotO += Math.round((rot - rotO) / 360.0F) * 360.0F; // Paper - stop large look changes from crashing the server - return Mth.lerp(0.2F, currentRotation, targetRotation); + return Mth.lerp(0.2F, rotO, rot); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch index c7c063146a24..a60b569a11de 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/projectile/ShulkerBullet.java +++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java @@ -55,7 +_,21 @@ - this.finalTarget = EntityReference.of(finalTarget); + this.finalTarget = EntityReference.of(target); this.currentMoveDirection = Direction.UP; - this.selectNextMoveDirection(axis, finalTarget); + this.selectNextMoveDirection(invalidStartAxis, target); - } -+ this.projectileSource = shooter.getBukkitLivingEntity(); // CraftBukkit ++ this.projectileSource = owner.getBukkitLivingEntity(); // CraftBukkit + } + + // CraftBukkit start @@ -32,7 +32,7 @@ } } -@@ -220,7 +_,7 @@ +@@ -218,7 +_,7 @@ } if (hitResult != null && this.isAlive() && hitResult.getType() != HitResult.Type.MISS) { @@ -41,16 +41,16 @@ } ProjectileUtil.rotateTowardsMovement(this, 0.5F); -@@ -293,7 +_,7 @@ +@@ -288,7 +_,7 @@ } - if (entity instanceof LivingEntity livingEntity1) { -- livingEntity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this)); -+ livingEntity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + if (target instanceof LivingEntity livingTarget) { +- livingTarget.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this)); ++ livingTarget.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(owner, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } } -@@ -306,14 +_,20 @@ +@@ -301,14 +_,20 @@ } private void destroy() { @@ -66,19 +66,19 @@ } @Override - protected void onHit(HitResult result) { - super.onHit(result); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); - this.destroy(); + this.destroy(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } @Override -@@ -328,9 +_,14 @@ +@@ -323,9 +_,14 @@ @Override - public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { + public boolean hurtServer(final ServerLevel level, final DamageSource source, final float damage) { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, false)) { + return false; + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch index c46b5f9bdd1f..afa84e5943d2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch @@ -3,9 +3,9 @@ @@ -60,7 +_,7 @@ this.applyEffectsFromBlocks(); super.tick(); - if (hitResultOnMoveVector.getType() != HitResult.Type.MISS && this.isAlive()) { -- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); -+ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + if (result.getType() != HitResult.Type.MISS && this.isAlive()) { +- this.hitTargetOrDeflectSelf(result); ++ this.preHitTargetOrDeflectSelf(result); // CraftBukkit - projectile hit event } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch index bb72fda9f12a..61080a99da0f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java +++ b/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java -@@ -86,7 +_,14 @@ - protected AbstractArrow( - EntityType type, double x, double y, double z, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon +@@ -92,7 +_,14 @@ + final ItemStack pickupItemStack, + final @Nullable ItemStack firedFromWeapon ) { + // CraftBukkit start - handle the owner before the rest of things + this(type, x, y, z, level, pickupItemStack, firedFromWeapon, null); @@ -14,21 +14,21 @@ + // CraftBukkit end this.pickupItemStack = pickupItemStack.copy(); this.applyComponentsFromItemStack(pickupItemStack); - Unit unit = pickupItemStack.remove(DataComponents.INTANGIBLE_PROJECTILE); -@@ -111,8 +_,8 @@ - protected AbstractArrow( - EntityType type, LivingEntity owner, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon + Unit intangible = pickupItemStack.remove(DataComponents.INTANGIBLE_PROJECTILE); +@@ -121,8 +_,8 @@ + final ItemStack pickupItemStack, + final @Nullable ItemStack firedFromWeapon ) { -- this(type, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon); -- this.setOwner(owner); -+ this(type, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon, owner); // CraftBukkit -+ // this.setOwner(owner); // SPIGOT-7744 - Moved to the above constructor +- this(type, mob.getX(), mob.getEyeY() - 0.1F, mob.getZ(), level, pickupItemStack, firedFromWeapon); +- this.setOwner(mob); ++ this(type, mob.getX(), mob.getEyeY() - 0.1F, mob.getZ(), level, pickupItemStack, firedFromWeapon, mob); // CraftBukkit ++ // this.setOwner(mob); // SPIGOT-7744 - Moved to the above constructor } - public void setSoundEvent(SoundEvent soundEvent) { -@@ -146,7 +_,11 @@ + public void setSoundEvent(final SoundEvent soundEvent) { +@@ -156,7 +_,11 @@ @Override - public void lerpMotion(Vec3 movement) { + public void lerpMotion(final Vec3 movement) { super.lerpMotion(movement); - this.life = 0; + // Paper start - Fix loophole for arrow immunity @@ -39,7 +39,7 @@ if (this.isInGround() && movement.lengthSqr() > 0.0) { this.setInGround(false); } -@@ -207,6 +_,10 @@ +@@ -217,6 +_,10 @@ this.setSharedFlagOnFire(this.getRemainingFireTicks() > 0); } } else { @@ -48,27 +48,27 @@ + if (maxArrowDespawnInvulnerability.enabled() && this.tickCount > maxArrowDespawnInvulnerability.intValue()) this.tickDespawn(); + // Paper end - tick life regardless after X seconds this.inGroundTime = 0; - Vec3 vec31 = this.position(); + Vec3 originalPosition = this.position(); if (this.isInWater()) { -@@ -276,7 +_,7 @@ +@@ -288,7 +_,7 @@ - if (list.isEmpty()) { - if (this.isAlive() && hitResult.getType() != HitResult.Type.MISS) { -- this.hitTargetOrDeflectSelf(hitResult); -+ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event + if (entitiesHit.isEmpty()) { + if (this.isAlive() && blockHitResult.getType() != HitResult.Type.MISS) { +- this.hitTargetOrDeflectSelf(blockHitResult); ++ this.preHitTargetOrDeflectSelf(blockHitResult); // CraftBukkit - projectile hit event this.needsSync = true; } break; -@@ -293,7 +_,7 @@ - - private ProjectileDeflection hitTargetsOrDeflectSelf(Collection hitResults) { - for (EntityHitResult entityHitResult : hitResults) { -- ProjectileDeflection projectileDeflection = this.hitTargetOrDeflectSelf(entityHitResult); -+ ProjectileDeflection projectileDeflection = this.preHitTargetOrDeflectSelf(entityHitResult); // CraftBukkit - projectile hit event - if (!this.isAlive() || projectileDeflection != ProjectileDeflection.NONE) { - return projectileDeflection; +@@ -305,7 +_,7 @@ + + private ProjectileDeflection hitTargetsOrDeflectSelf(final Collection entityHitResults) { + for (EntityHitResult e : entityHitResults) { +- ProjectileDeflection deflection = this.hitTargetOrDeflectSelf(e); ++ ProjectileDeflection deflection = this.preHitTargetOrDeflectSelf(e); // CraftBukkit - projectile hit event + if (!this.isAlive() || deflection != ProjectileDeflection.NONE) { + return deflection; } -@@ -325,20 +_,37 @@ +@@ -337,20 +_,37 @@ } } @@ -108,7 +108,7 @@ } public boolean isInGround() { -@@ -364,8 +_,8 @@ +@@ -376,8 +_,8 @@ protected void tickDespawn() { this.life++; @@ -119,19 +119,19 @@ } } -@@ -399,9 +_,9 @@ +@@ -411,9 +_,9 @@ } @Override -- public void push(double x, double y, double z) { -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param +- public void push(final double xa, final double ya, final double za) { ++ public void push(final double xa, final double ya, final double za, final @Nullable Entity pushingEntity) { // Paper - add push source entity param if (!this.isInGround()) { -- super.push(x, y, z); -+ super.push(x, y, z, pushingEntity); // Paper - add push source entity param +- super.push(xa, ya, za); ++ super.push(xa, ya, za, pushingEntity); // Paper - add push source entity param } } -@@ -428,7 +_,7 @@ +@@ -440,7 +_,7 @@ } if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) { @@ -140,14 +140,14 @@ return; } -@@ -444,10 +_,16 @@ - livingEntity.setLastHurtMob(entity); +@@ -456,10 +_,16 @@ + livingOwner.setLastHurtMob(entity); } + if (this.isCritArrow()) damageSource = damageSource.critical(); // Paper - add critical damage API - boolean flag = entity.getType() == EntityType.ENDERMAN; + boolean isEnderman = entity.is(EntityType.ENDERMAN); int remainingFireTicks = entity.getRemainingFireTicks(); - if (this.isOnFire() && !flag) { + if (this.isOnFire() && !isEnderman) { - entity.igniteForSeconds(5.0F); + // CraftBukkit start + org.bukkit.event.entity.EntityCombustByEntityEvent combustEvent = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5.0F); @@ -157,8 +157,8 @@ + // CraftBukkit end } - if (entity.hurtOrSimulate(damageSource, ceil)) { -@@ -485,7 +_,7 @@ + if (entity.hurtOrSimulate(damageSource, damage)) { +@@ -497,7 +_,7 @@ this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); if (this.getPierceLevel() <= 0) { @@ -167,8 +167,8 @@ } } else { entity.setRemainingFireTicks(remainingFireTicks); -@@ -496,7 +_,7 @@ - this.spawnAtLocation(serverLevel2, this.getPickupItem(), 0.1F); +@@ -508,7 +_,7 @@ + this.spawnAtLocation(level, this.getPickupItem(), 0.1F); } - this.discard(); @@ -176,40 +176,40 @@ } } } -@@ -509,7 +_,7 @@ - double max = Math.max(0.0, 1.0 - entity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); - Vec3 vec3 = this.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(d * 0.6 * max); - if (vec3.lengthSqr() > 0.0) { -- entity.push(vec3.x, 0.1, vec3.z); -+ entity.push(vec3.x, 0.1, vec3.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent +@@ -521,7 +_,7 @@ + double knockbackResistance = Math.max(0.0, 1.0 - mob.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); + Vec3 movement = this.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(knockback * 0.6 * knockbackResistance); + if (movement.lengthSqr() > 0.0) { +- mob.push(movement.x, 0.1, movement.z); ++ mob.push(movement.x, 0.1, movement.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent } } } -@@ -620,7 +_,14 @@ +@@ -632,7 +_,14 @@ @Override - public void setOwner(@Nullable Entity entity) { + public void setOwner(final @Nullable Entity owner) { + // Paper start - Fix PickupStatus getting reset -+ this.setOwner(entity, true); ++ this.setOwner(owner, true); + } + -+ public void setOwner(@Nullable Entity entity, boolean resetPickup) { ++ public void setOwner(final @Nullable Entity owner, final boolean resetPickup) { + // Paper end - Fix PickupStatus getting reset - super.setOwner(entity); + super.setOwner(owner); + if (!resetPickup) return; // Paper - Fix PickupStatus getting reset - this.pickup = switch (entity) { - case Player player when this.pickup == AbstractArrow.Pickup.DISALLOWED -> AbstractArrow.Pickup.ALLOWED; -@@ -632,9 +_,22 @@ + this.pickup = switch (owner) { + case Player ignored when this.pickup == AbstractArrow.Pickup.DISALLOWED -> AbstractArrow.Pickup.ALLOWED; +@@ -644,9 +_,22 @@ @Override - public void playerTouch(Player entity) { + public void playerTouch(final Player player) { if (!this.level().isClientSide() && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) { -- if (this.tryPickup(entity)) { +- if (this.tryPickup(player)) { + // CraftBukkit start + ItemStack itemstack = this.getPickupItem(); -+ if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && entity.getInventory().canHold(itemstack) > 0) { ++ if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && player.getInventory().canHold(itemstack) > 0) { + net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack); -+ org.bukkit.event.player.PlayerPickupArrowEvent event = new org.bukkit.event.player.PlayerPickupArrowEvent((org.bukkit.entity.Player) entity.getBukkitEntity(), (org.bukkit.entity.Item) item.getBukkitEntity(), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity()); ++ org.bukkit.event.player.PlayerPickupArrowEvent event = new org.bukkit.event.player.PlayerPickupArrowEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.Item) item.getBukkitEntity(), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity()); + // event.setCancelled(!entityhuman.canPickUpLoot); TODO + if (!event.callEvent()) { + return; @@ -217,9 +217,9 @@ + itemstack = item.getItem(); + } + -+ if ((this.pickup == AbstractArrow.Pickup.ALLOWED && entity.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && entity.getAbilities().instabuild)) { ++ if ((this.pickup == AbstractArrow.Pickup.ALLOWED && player.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && player.getAbilities().instabuild)) { + // CraftBukkit end - entity.take(this, 1); + player.take(this, 1); - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/Arrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/Arrow.java.patch index 55d81a23186f..e1c73cb88a51 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/Arrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/Arrow.java.patch @@ -3,9 +3,9 @@ @@ -115,7 +_,7 @@ Entity effectSource = this.getEffectSource(); PotionContents potionContents = this.getPotionContents(); - float potionDurationScale = this.getPotionDurationScale(); -- potionContents.forEachEffect(mobEffectInstance -> target.addEffect(mobEffectInstance, effectSource), potionDurationScale); -+ potionContents.forEachEffect(mobEffectInstance -> target.addEffect(mobEffectInstance, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW), potionDurationScale); // CraftBukkit + float durationScale = this.getPotionDurationScale(); +- potionContents.forEachEffect(effect -> mob.addEffect(effect, effectSource), durationScale); ++ potionContents.forEachEffect(effect -> mob.addEffect(effect, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW), durationScale); // CraftBukkit } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java.patch index a44b58670aa4..706a0a310a9b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java +++ b/net/minecraft/world/entity/projectile/arrow/SpectralArrow.java -@@ -41,7 +_,7 @@ - protected void doPostHurtEffects(LivingEntity target) { - super.doPostHurtEffects(target); - MobEffectInstance mobEffectInstance = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0); -- target.addEffect(mobEffectInstance, this.getEffectSource()); -+ target.addEffect(mobEffectInstance, this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit +@@ -43,7 +_,7 @@ + protected void doPostHurtEffects(final LivingEntity mob) { + super.doPostHurtEffects(mob); + MobEffectInstance effect = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0); +- mob.addEffect(effect, this.getEffectSource()); ++ mob.addEffect(effect, this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch index 0e745702adcb..684f6afb5484 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java +++ b/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java @@ -51,6 +_,12 @@ - this.entityData.set(ID_FOIL, pickupItemStack.hasFoil()); + this.entityData.set(ID_FOIL, tridentItem.hasFoil()); } + // Paper start - Allow trident custom damage @@ -11,16 +11,16 @@ + // Paper end - Allow trident custom damage + @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); + protected void defineSynchedData(final SynchedEntityData.Builder entityData) { + super.defineSynchedData(entityData); @@ -72,10 +_,10 @@ - this.spawnAtLocation(serverLevel, this.getPickupItem(), 0.1F); + this.spawnAtLocation(level, this.getPickupItem(), 0.1F); } - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause } else { - if (!(owner instanceof Player) && this.position().distanceTo(owner.getEyePosition()) < owner.getBbWidth() + 1.0) { + if (!(currentOwner instanceof Player) && this.position().distanceTo(currentOwner.getEyePosition()) < currentOwner.getBbWidth() + 1.0) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause return; @@ -45,14 +45,14 @@ + // Paper end + @Override - protected @Nullable EntityHitResult findHitEntity(Vec3 startVec, Vec3 endVec) { - return this.dealtDamage ? null : super.findHitEntity(startVec, endVec); + protected @Nullable EntityHitResult findHitEntity(final Vec3 from, final Vec3 to) { + return this.dealtDamage ? null : super.findHitEntity(from, to); @@ -118,7 +_,7 @@ @Override - protected void onHitEntity(EntityHitResult result) { - Entity entity = result.getEntity(); -- float f = 8.0F; -+ float f = (float) this.baseDamage; // Paper - Allow trident custom damage - Entity owner = this.getOwner(); - DamageSource damageSource = this.damageSources().trident(this, (Entity)(owner == null ? this : owner)); + protected void onHitEntity(final EntityHitResult hitResult) { + Entity entity = hitResult.getEntity(); +- float dmg = 8.0F; ++ float dmg = (float) this.baseDamage; // Paper - Allow trident custom damage + Entity currentOwner = this.getOwner(); + DamageSource damageSource = this.damageSources().trident(this, (Entity)(currentOwner == null ? this : currentOwner)); if (this.level() instanceof ServerLevel serverLevel) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/AbstractHurtingProjectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/AbstractHurtingProjectile.java.patch index 9eb8af597e53..9f59be1d928a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/AbstractHurtingProjectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/AbstractHurtingProjectile.java.patch @@ -7,14 +7,14 @@ + public float bukkitYield = 1; // CraftBukkit + public boolean isIncendiary = true; // CraftBukkit - protected AbstractHurtingProjectile(EntityType type, Level level) { + protected AbstractHurtingProjectile(final EntityType type, final Level level) { super(type, level); -@@ -86,12 +_,12 @@ +@@ -92,12 +_,12 @@ } - if (hitResultOnMoveVector.getType() != HitResult.Type.MISS && this.isAlive()) { -- this.hitTargetOrDeflectSelf(hitResultOnMoveVector); -+ this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event + if (hitResult.getType() != HitResult.Type.MISS && this.isAlive()) { +- this.hitTargetOrDeflectSelf(hitResult); ++ this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event } this.createParticleTrail(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/DragonFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/DragonFireball.java.patch index 0f3dffb6cd05..e13954640c9b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/DragonFireball.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/DragonFireball.java.patch @@ -4,12 +4,12 @@ } } -+ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), entitiesOfClass.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) areaEffectCloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events ++ if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), entitiesOfClass.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) cloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events this.level().levelEvent(LevelEvent.PARTICLES_DRAGON_FIREBALL_SPLASH, this.blockPosition(), this.isSilent() ? -1 : 1); -- this.level().addFreshEntity(areaEffectCloud); +- this.level().addFreshEntity(cloud); - this.discard(); -+ this.level().addFreshEntity(areaEffectCloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason -+ } else areaEffectCloud.discard(null); // Paper - EnderDragon Events ++ this.level().addFreshEntity(cloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason ++ } else cloud.discard(null); // Paper - EnderDragon Events + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java.patch index 68379e517009..084ee5d2c013 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java.patch @@ -2,25 +2,25 @@ +++ b/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java @@ -20,20 +_,27 @@ - public LargeFireball(EntityType type, Level level) { + public LargeFireball(final EntityType type, final Level level) { super(type, level); + this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit } - public LargeFireball(Level level, LivingEntity owner, Vec3 movement, int explosionPower) { - super(EntityType.FIREBALL, owner, movement, level); + public LargeFireball(final Level level, final LivingEntity mob, final Vec3 direction, final int explosionPower) { + super(EntityType.FIREBALL, mob, direction, level); this.explosionPower = explosionPower; + this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit } @Override - protected void onHit(HitResult result) { - super.onHit(result); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); if (this.level() instanceof ServerLevel serverLevel) { -- boolean flag = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); -- this.level().explode(this, this.getX(), this.getY(), this.getZ(), this.explosionPower, flag, Level.ExplosionInteraction.MOB); +- boolean grief = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), this.explosionPower, grief, Level.ExplosionInteraction.MOB); - this.discard(); -+ // boolean flag = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit - baked into fields (see constructor) ++ // boolean grief = serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); // CraftBukkit - baked into fields (see constructor) + // CraftBukkit start - fire ExplosionPrimeEvent + org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); + if (event.callEvent()) { @@ -33,7 +33,7 @@ @@ -58,6 +_,6 @@ @Override - protected void readAdditionalSaveData(ValueInput input) { + protected void readAdditionalSaveData(final ValueInput input) { super.readAdditionalSaveData(input); - this.explosionPower = input.getByteOr("ExplosionPower", (byte)1); + this.bukkitYield = this.explosionPower = input.getByteOr("ExplosionPower", (byte)1); // CraftBukkit - set bukkitYield when setting explosionPower diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java.patch index 59a16e4ae357..0d214aca2064 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java @@ -23,6 +_,11 @@ - public SmallFireball(Level level, LivingEntity owner, Vec3 movement) { - super(EntityType.SMALL_FIREBALL, owner, movement, level); + public SmallFireball(final Level level, final LivingEntity mob, final Vec3 direction) { + super(EntityType.SMALL_FIREBALL, mob, direction, level); + // CraftBukkit start + if (this.getOwner() != null && this.getOwner() instanceof Mob) { + this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING); @@ -11,9 +11,9 @@ + // CraftBukkit end } - public SmallFireball(Level level, double x, double y, double z, Vec3 movement) { + public SmallFireball(final Level level, final double x, final double y, final double z, final Vec3 direction) { @@ -36,7 +_,14 @@ - Entity var7 = result.getEntity(); + Entity var7 = hitResult.getEntity(); Entity owner = this.getOwner(); int remainingFireTicks = var7.getRemainingFireTicks(); - var7.igniteForSeconds(5.0F); @@ -29,20 +29,20 @@ if (!var7.hurtServer(serverLevel, damageSource, 5.0F)) { var7.setRemainingFireTicks(remainingFireTicks); @@ -51,9 +_,9 @@ - super.onHitBlock(result); + super.onHitBlock(hitResult); if (this.level() instanceof ServerLevel serverLevel) { Entity owner = this.getOwner(); - if (!(owner instanceof Mob) || serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) { + if (this.isIncendiary) { // CraftBukkit - BlockPos blockPos = result.getBlockPos().relative(result.getDirection()); -- if (this.level().isEmptyBlock(blockPos)) { -+ if (this.level().isEmptyBlock(blockPos) && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos, this).isCancelled()) { // CraftBukkit - this.level().setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level(), blockPos)); + BlockPos pos = hitResult.getBlockPos().relative(hitResult.getDirection()); +- if (this.level().isEmptyBlock(pos)) { ++ if (this.level().isEmptyBlock(pos) && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), pos, this).isCancelled()) { // CraftBukkit + this.level().setBlockAndUpdate(pos, BaseFireBlock.getState(this.level(), pos)); } } @@ -64,7 +_,7 @@ - protected void onHit(HitResult result) { - super.onHit(result); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); if (!this.level().isClientSide()) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java.patch index 427e628f7980..ee9ee10a94b3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/WitherSkull.java.patch @@ -4,28 +4,28 @@ if (var8.isAlive()) { EnchantmentHelper.doPostAttackEffects(serverLevel, var8, damageSource); } else { -- livingEntity.heal(5.0F); -+ livingEntity.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit +- livingOwner.heal(5.0F); ++ livingOwner.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit } } } else { -- flag = var8.hurtServer(serverLevel, this.damageSources().magic(), 5.0F); -+ flag = var8.hurtServer(serverLevel, this.damageSources().magic().eventEntityDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API +- wasHurt = var8.hurtServer(serverLevel, this.damageSources().magic(), 5.0F); ++ wasHurt = var8.hurtServer(serverLevel, this.damageSources().magic().eventEntityDamager(this), 5.0F); // Paper - Fire EntityDamageByEntityEvent for unowned wither skulls // Paper - fix DamageSource API } - if (flag && var8 instanceof LivingEntity livingEntityx) { + if (wasHurt && var8 instanceof LivingEntity livingEntity) { @@ -83,7 +_,7 @@ } - if (i > 0) { -- livingEntityx.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource()); -+ livingEntityx.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + if (witherSeconds > 0) { +- livingEntity.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * witherSeconds, 1), this.getEffectSource()); ++ livingEntity.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * witherSeconds, 1), this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } } @@ -93,8 +_,13 @@ - protected void onHit(HitResult result) { - super.onHit(result); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); if (!this.level().isClientSide()) { - this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, Level.ExplosionInteraction.MOB); - this.discard(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java.patch index 503b3602f153..8b49c138e55b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java.patch @@ -1,33 +1,33 @@ --- a/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java +++ b/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/AbstractWindCharge.java -@@ -85,7 +_,7 @@ +@@ -89,7 +_,7 @@ } @Override -- public void push(double x, double y, double z) { -+ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent +- public void push(final double xa, final double ya, final double za) { ++ public void push(final double xa, final double ya, final double za, @Nullable Entity pushingEntity) { // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent } - public abstract void explode(Vec3 pos); -@@ -98,7 +_,7 @@ - Vec3 vec3 = Vec3.atLowerCornerOf(unitVec3i).multiply(0.25, 0.25, 0.25); - Vec3 vec31 = result.getLocation().add(vec3); - this.explode(vec31); + public abstract void explode(final Vec3 position); +@@ -102,7 +_,7 @@ + Vec3 scaledNormal = Vec3.atLowerCornerOf(collisionNormal).multiply(0.25, 0.25, 0.25); + Vec3 explosionPos = hitResult.getLocation().add(scaledNormal); + this.explode(explosionPos); - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } -@@ -106,7 +_,7 @@ - protected void onHit(HitResult result) { - super.onHit(result); +@@ -110,7 +_,7 @@ + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); if (!this.level().isClientSide()) { - this.discard(); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } -@@ -139,7 +_,7 @@ +@@ -143,7 +_,7 @@ public void tick() { if (!this.level().isClientSide() && this.getBlockY() > this.level().getMaxY() + 30) { this.explode(this.position()); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/BreezeWindCharge.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/BreezeWindCharge.java.patch index c2905d1cb136..1cc4e7797769 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/BreezeWindCharge.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/BreezeWindCharge.java.patch @@ -3,7 +3,7 @@ @@ -21,6 +_,12 @@ @Override - public void explode(Vec3 pos) { + public void explode(final Vec3 position) { + // Paper start - Fire event for WindCharge explosions + org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, RADIUS, false); + if (event.isCancelled()) { @@ -14,9 +14,9 @@ .explode( this, @@ -29,8 +_,8 @@ - pos.x(), - pos.y(), - pos.z(), + position.x(), + position.y(), + position.z(), - 3.0F, - false, + event.getRadius(), // Paper - Fire event for WindCharge explosions diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java.patch index a4a45fc9312a..9248bff35d6a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java +++ b/net/minecraft/world/entity/projectile/hurtingprojectile/windcharge/WindCharge.java -@@ -54,6 +_,12 @@ +@@ -59,6 +_,12 @@ @Override - public void explode(Vec3 pos) { + public void explode(final Vec3 position) { + // Paper start - Fire event for WindCharge explosions + org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, RADIUS, false); + if (event.isCancelled()) { @@ -13,10 +13,10 @@ this.level() .explode( this, -@@ -62,8 +_,8 @@ - pos.x(), - pos.y(), - pos.z(), +@@ -67,8 +_,8 @@ + position.x(), + position.y(), + position.z(), - 1.2F, - false, + event.getRadius(), // Paper - Fire event for WindCharge explosions diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java.patch index 69d4e6502d60..d6ec47d1482a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java.patch @@ -1,65 +1,65 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/AbstractThrownPotion.java -@@ -68,56 +_,97 @@ +@@ -70,56 +_,97 @@ @Override - protected void onHit(HitResult result) { - super.onHit(result); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); + // Paper start - More projectile API -+ this.splash(result); ++ this.splash(hitResult); + } + -+ public void splash(HitResult result) { ++ public void splash(final HitResult hitResult) { + // Paper end - More projectile API - if (this.level() instanceof ServerLevel serverLevel) { - ItemStack item = this.getItem(); - PotionContents potionContents = item.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + if (this.level() instanceof ServerLevel level) { + ItemStack potionItemStack = this.getItem(); + PotionContents potion = potionItemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + boolean showParticles = true; // Paper - Fix potions splash events - if (potionContents.is(Potions.WATER)) { -- this.onHitAsWater(serverLevel); -- } else if (potionContents.hasEffects()) { -- this.onHitAsPotion(serverLevel, item, result); -+ showParticles = this.onHitAsWater(serverLevel, result); // Paper - Fix potions splash events -+ } else if (true || potionContents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply -+ showParticles = this.onHitAsPotion(serverLevel, item, result); // Paper - pass HitResult + if (potion.is(Potions.WATER)) { +- this.onHitAsWater(level); +- } else if (potion.hasEffects()) { +- this.onHitAsPotion(level, potionItemStack, hitResult); ++ showParticles = this.onHitAsWater(level, hitResult); // Paper - Fix potions splash events ++ } else if (true || potion.hasEffects()) { // CraftBukkit - Call event even if no effects to apply ++ showParticles = this.onHitAsPotion(level, potionItemStack, hitResult); // Paper - pass HitResult } + if (showParticles) { // Paper - Fix potions splash events - int i = potionContents.potion().isPresent() && potionContents.potion().get().value().hasInstantEffects() + int type = potion.potion().isPresent() && potion.potion().get().value().hasInstantEffects() ? LevelEvent.PARTICLES_INSTANT_POTION_SPLASH : LevelEvent.PARTICLES_SPELL_POTION_SPLASH; - serverLevel.levelEvent(i, this.blockPosition(), potionContents.getColor()); + level.levelEvent(type, this.blockPosition(), potion.getColor()); - this.discard(); + } // Paper - Fix potions splash events + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } } -- private void onHitAsWater(ServerLevel level) { +- private void onHitAsWater(final ServerLevel level) { + private static final Predicate APPLY_WATER_GET_ENTITIES_PREDICATE = AbstractThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events + -+ private boolean onHitAsWater(ServerLevel level, HitResult result) { // Paper - Fix potions splash events ++ private boolean onHitAsWater(final ServerLevel level, final HitResult hitResult) { // Paper - Fix potions splash events AABB aabb = this.getBoundingBox().inflate(4.0, 2.0, 4.0); -- for (LivingEntity livingEntity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, WATER_SENSITIVE_OR_ON_FIRE)) { +- for (LivingEntity entity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, WATER_SENSITIVE_OR_ON_FIRE)) { + // Paper start - Fix potions splash events + java.util.Map affected = new java.util.HashMap<>(); + java.util.Set rehydrate = new java.util.HashSet<>(); + java.util.Set extinguish = new java.util.HashSet<>(); -+ for (LivingEntity livingEntity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, APPLY_WATER_GET_ENTITIES_PREDICATE)) { -+ if (livingEntity instanceof Axolotl axolotl) { ++ for (LivingEntity entity : this.level().getEntitiesOfClass(LivingEntity.class, aabb, APPLY_WATER_GET_ENTITIES_PREDICATE)) { ++ if (entity instanceof Axolotl axolotl) { + rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity())); + } + // Paper end - Fix potions splash events - double d = this.distanceToSqr(livingEntity); - if (d < 16.0) { - if (livingEntity.isSensitiveToWater()) { -- livingEntity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); -+ affected.put(livingEntity.getBukkitLivingEntity(), 1.0); // Paper - Fix potions splash events + double dist = this.distanceToSqr(entity); + if (dist < 16.0) { + if (entity.isSensitiveToWater()) { +- entity.hurtServer(level, this.damageSources().indirectMagic(this, this.getOwner()), 1.0F); ++ affected.put(entity.getBukkitLivingEntity(), 1.0); // Paper - Fix potions splash events } - if (livingEntity.isOnFire() && livingEntity.isAlive()) { -- livingEntity.extinguishFire(); -+ extinguish.add(livingEntity.getBukkitLivingEntity()); // Paper - Fix potions splash events + if (entity.isOnFire() && entity.isAlive()) { +- entity.extinguishFire(); ++ extinguish.add(entity.getBukkitLivingEntity()); // Paper - Fix potions splash events } } } @@ -68,7 +68,7 @@ - axolotl.rehydrate(); + // Paper start - Fix potions splash events + io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent( -+ this, result, affected, rehydrate, extinguish ++ this, hitResult, affected, rehydrate, extinguish + ); + if (!event.isCancelled()) { + for (org.bukkit.entity.LivingEntity affectedEntity : event.getToDamage()) { @@ -87,10 +87,10 @@ + return !event.isCancelled(); // Paper - Fix potions splash events } -- protected abstract void onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult); -+ protected abstract boolean onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult); // Paper - Fix potions splash events & More Projectile API +- protected abstract void onHitAsPotion(ServerLevel level, ItemStack potionItem, HitResult hitResult); ++ protected abstract boolean onHitAsPotion(ServerLevel level, ItemStack potionItem, HitResult hitResult); // Paper - Fix potions splash events & More Projectile API - private void dowseFire(BlockPos pos) { + private void dowseFire(final BlockPos pos) { BlockState blockState = this.level().getBlockState(pos); if (blockState.is(BlockTags.FIRE)) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch index 5ce544f89f5f..ece99bf0170f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java -@@ -62,7 +_,7 @@ - super.onHit(result); +@@ -65,7 +_,7 @@ + super.onHit(hitResult); if (!this.level().isClientSide()) { this.level().broadcastEntityEvent(this, EntityEvent.DEATH); - this.discard(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java.patch index 1c7b472ff8d8..8969dcd4c4c3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java.patch @@ -1,44 +1,44 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEgg.java -@@ -62,31 +_,66 @@ - protected void onHit(HitResult result) { - super.onHit(result); +@@ -66,29 +_,64 @@ + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); if (!this.level().isClientSide()) { - if (this.random.nextInt(8) == 0) { + // CraftBukkit start + boolean hatching = this.random.nextInt(8) == 0; + if (true) { + // CraftBukkit end - int i = 1; + int count = 1; if (this.random.nextInt(32) == 0) { - i = 4; + count = 4; } + // CraftBukkit start + if (!hatching) { -+ i = 0; ++ count = 0; + } + + net.minecraft.world.entity.Entity shooter = this.getOwner(); + org.bukkit.entity.EntityType hatchingType = org.bukkit.entity.EntityType.CHICKEN; + if (shooter instanceof net.minecraft.server.level.ServerPlayer) { -+ org.bukkit.event.player.PlayerEggThrowEvent event = new org.bukkit.event.player.PlayerEggThrowEvent((org.bukkit.entity.Player) shooter.getBukkitEntity(), (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) i, hatchingType); ++ org.bukkit.event.player.PlayerEggThrowEvent event = new org.bukkit.event.player.PlayerEggThrowEvent((org.bukkit.entity.Player) shooter.getBukkitEntity(), (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) count, hatchingType); + event.callEvent(); + + hatching = event.isHatching(); -+ i = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 ++ count = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 + hatchingType = event.getHatchingType(); + } + // CraftBukkit end + // Paper start - Add ThrownEggHatchEvent -+ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, (byte) i, hatchingType); ++ com.destroystokyo.paper.event.entity.ThrownEggHatchEvent event = new com.destroystokyo.paper.event.entity.ThrownEggHatchEvent((org.bukkit.entity.Egg) getBukkitEntity(), hatching, (byte) count, hatchingType); + event.callEvent(); + hatching = event.isHatching(); -+ i = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 ++ count = hatching ? event.getNumHatches() : 0; // If hatching is set to false, ensure child count is 0 + hatchingType = event.getHatchingType(); + EntityType newEntityType = org.bukkit.craftbukkit.entity.CraftEntityType.bukkitToMinecraft(hatchingType); + // Paper end - Add ThrownEggHatchEvent - for (int i1 = 0; i1 < i; i1++) { + for (int i = 0; i < count; i++) { - Chicken chicken = EntityType.CHICKEN.create(this.level(), EntitySpawnReason.TRIGGERED); + net.minecraft.world.entity.Entity chicken = newEntityType.create(this.level(), net.minecraft.world.entity.EntitySpawnReason.TRIGGERED); // CraftBukkit if (chicken != null) { @@ -49,14 +49,10 @@ + } + // CraftBukkit end chicken.snapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); -- Optional.ofNullable(this.getItem().get(DataComponents.CHICKEN_VARIANT)) -- .flatMap(eitherHolder -> eitherHolder.unwrap(this.registryAccess())) -- .ifPresent(chicken::setVariant); +- Optional.ofNullable(this.getItem().get(DataComponents.CHICKEN_VARIANT)).ifPresent(chicken::setVariant); + // CraftBukkit start + if (chicken instanceof Chicken realChicken) { -+ Optional.ofNullable(this.getItem().get(DataComponents.CHICKEN_VARIANT)) -+ .flatMap(eitherHolder -> eitherHolder.unwrap(this.registryAccess())) -+ .ifPresent(realChicken::setVariant); ++ Optional.ofNullable(this.getItem().get(DataComponents.CHICKEN_VARIANT)).ifPresent(realChicken::setVariant); + } + // CraftBukkit end if (!chicken.fudgePositionAfterSizeChange(ZERO_SIZED_DIMENSIONS)) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java.patch index 5baf743b58a9..6b6532ae31bf 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java.patch @@ -1,26 +1,27 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java -@@ -102,11 +_,21 @@ - Vec3 vec3 = this.oldPosition(); - if (owner instanceof ServerPlayer serverPlayer) { - if (serverPlayer.connection.isAcceptingMessages()) { +@@ -102,11 +_,22 @@ + Vec3 teleportPos = this.oldPosition(); + if (owner instanceof ServerPlayer player) { + if (player.connection.isAcceptingMessages()) { + // CraftBukkit start + // Store pre teleportation position as the teleport has been moved up. -+ final double preTeleportX = serverPlayer.getX(), preTeleportY = serverPlayer.getY(), preTeleportZ = serverPlayer.getZ(); -+ final float preTeleportYRot = serverPlayer.getYRot(), preTeleportXRot = serverPlayer.getXRot(); -+ ServerPlayer serverPlayer1 = serverPlayer.teleport(new TeleportTransition(serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); -+ if (serverPlayer1 == null) { ++ final double preTeleportX = player.getX(), preTeleportY = player.getY(), preTeleportZ = player.getZ(); ++ final float preTeleportYRot = player.getYRot(), preTeleportXRot = player.getXRot(); ++ ServerPlayer newOwner = player.teleport(new TeleportTransition( ++ level, teleportPos, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); ++ if (newOwner == null) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); + return; + } + // CraftBukkit end - if (this.random.nextFloat() < 0.05F && serverLevel.isSpawningMonsters()) { - Endermite endermite = EntityType.ENDERMITE.create(serverLevel, EntitySpawnReason.TRIGGERED); + if (this.random.nextFloat() < 0.05F && level.isSpawningMonsters()) { + Endermite endermite = EntityType.ENDERMITE.create(level, EntitySpawnReason.TRIGGERED); if (endermite != null) { - endermite.snapTo(owner.getX(), owner.getY(), owner.getZ(), owner.getYRot(), owner.getXRot()); -- serverLevel.addFreshEntity(endermite); +- level.addFreshEntity(endermite); + endermite.snapTo(preTeleportX, preTeleportY, preTeleportZ, preTeleportYRot, preTeleportXRot); // Paper - spawn endermite at pre teleport position as teleport has been moved up -+ serverLevel.addFreshEntity(endermite, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENDER_PEARL); // Paper - add reason ++ level.addFreshEntity(endermite, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENDER_PEARL); // Paper - add reason } } @@ -28,28 +29,28 @@ owner.setPortalCooldown(); } -- ServerPlayer serverPlayer1 = serverPlayer.teleport( +- ServerPlayer newOwner = player.teleport( - new TeleportTransition( -- serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING +- level, teleportPos, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING - ) - ); + // CraftBukkit start - moved up -+ // ServerPlayer serverPlayer1 = serverPlayer.teleport( ++ // ServerPlayer newOwner = player.teleport( + // new TeleportTransition( -+ // serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING ++ // level, teleportPos, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING + // ) + // ); + // CraftBukkit end - moved up - if (serverPlayer1 != null) { - serverPlayer1.resetFallDistance(); - serverPlayer1.resetCurrentImpulseContext(); -- serverPlayer1.hurtServer(serverPlayer.level(), this.damageSources().enderPearl(), 5.0F); -+ serverPlayer1.hurtServer(serverPlayer.level(), this.damageSources().enderPearl().eventEntityDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API + if (newOwner != null) { + newOwner.resetFallDistance(); + newOwner.resetCurrentImpulseContext(); +- newOwner.hurtServer(player.level(), this.damageSources().enderPearl(), 5.0F); ++ newOwner.hurtServer(player.level(), this.damageSources().enderPearl().eventEntityDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API } - this.playSound(serverLevel, vec3); -@@ -138,9 +_,9 @@ - this.playSound(serverLevel, vec3); + this.playSound(level, teleportPos); +@@ -142,9 +_,9 @@ + this.playSound(level, teleportPos); } - this.discard(); @@ -60,8 +61,8 @@ } } } -@@ -163,7 +_,7 @@ - && !entity.isAlive() +@@ -167,7 +_,7 @@ + && !owner.isAlive() && !serverPlayer.wonGame && serverPlayer.level().getGameRules().get(GameRules.ENDER_PEARLS_VANISH_ON_DEATH)) { - this.discard(); @@ -69,21 +70,21 @@ } else { super.tick(); } -@@ -192,7 +_,7 @@ - public @Nullable Entity teleport(TeleportTransition teleportTransition) { - Entity entity = super.teleport(teleportTransition); - if (entity != null) { -- entity.placePortalTicket(BlockPos.containing(entity.position())); -+ if (!this.level().paperConfig().misc.legacyEnderPearlBehavior) entity.placePortalTicket(BlockPos.containing(entity.position())); // Paper - Allow using old ender pearl behavior +@@ -196,7 +_,7 @@ + public @Nullable Entity teleport(final TeleportTransition transition) { + Entity newEntity = super.teleport(transition); + if (newEntity != null) { +- newEntity.placePortalTicket(BlockPos.containing(newEntity.position())); ++ if (!this.level().paperConfig().misc.legacyEnderPearlBehavior) newEntity.placePortalTicket(BlockPos.containing(newEntity.position())); // Paper - Allow using old ender pearl behavior } - return entity; -@@ -200,7 +_,7 @@ + return newEntity; +@@ -204,7 +_,7 @@ @Override - public boolean canTeleport(Level fromLevel, Level toLevel) { -- return fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD && this.getOwner() instanceof ServerPlayer serverPlayer -+ return fromLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END && toLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && this.getOwner() instanceof ServerPlayer serverPlayer // CraftBukkit - ? super.canTeleport(fromLevel, toLevel) && serverPlayer.seenCredits - : super.canTeleport(fromLevel, toLevel); + public boolean canTeleport(final Level from, final Level to) { +- return from.dimension() == Level.END && to.dimension() == Level.OVERWORLD && this.getOwner() instanceof ServerPlayer player ++ return from.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END && to.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && this.getOwner() instanceof ServerPlayer player // CraftBukkit + ? super.canTeleport(from, to) && player.seenCredits + : super.canTeleport(from, to); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java.patch index b4cb035bba5c..15d79a480337 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownExperienceBottle.java @@ -40,16 +_,25 @@ - protected void onHit(HitResult result) { - super.onHit(result); - if (this.level() instanceof ServerLevel serverLevel) { -- serverLevel.levelEvent(LevelEvent.PARTICLES_SPELL_POTION_SPLASH, this.blockPosition(), -13083194); + protected void onHit(final HitResult hitResult) { + super.onHit(hitResult); + if (this.level() instanceof ServerLevel level) { +- level.levelEvent(LevelEvent.PARTICLES_SPELL_POTION_SPLASH, this.blockPosition(), -13083194); + // CraftBukkit - moved to after event - int i = 3 + serverLevel.random.nextInt(5) + serverLevel.random.nextInt(5); + int xpCount = 3 + this.random.nextInt(5) + this.random.nextInt(5); + // Paper start - exp bottle event -+ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, result, i); -+ i = event.getExperience(); ++ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, hitResult, xpCount); ++ xpCount = event.getExperience(); + // Paper end - exp bottle event - if (result instanceof BlockHitResult blockHitResult) { - Vec3 unitVec3 = blockHitResult.getDirection().getUnitVec3(); -- ExperienceOrb.awardWithDirection(serverLevel, result.getLocation(), unitVec3, i); -+ ExperienceOrb.awardWithDirection(serverLevel, result.getLocation(), unitVec3, i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper + if (hitResult instanceof BlockHitResult blockHitResult) { + Vec3 blockNormalHit = blockHitResult.getDirection().getUnitVec3(); +- ExperienceOrb.awardWithDirection(level, hitResult.getLocation(), blockNormalHit, xpCount); ++ ExperienceOrb.awardWithDirection(level, hitResult.getLocation(), blockNormalHit, xpCount, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper } else { -- ExperienceOrb.awardWithDirection(serverLevel, result.getLocation(), this.getDeltaMovement().scale(-1.0), i); +- ExperienceOrb.awardWithDirection(level, hitResult.getLocation(), this.getDeltaMovement().scale(-1.0), xpCount); - } -+ ExperienceOrb.awardWithDirection(serverLevel, result.getLocation(), this.getDeltaMovement().scale(-1.0), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper ++ ExperienceOrb.awardWithDirection(level, hitResult.getLocation(), this.getDeltaMovement().scale(-1.0), xpCount, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper + } + // Paper start - exp bottle event + if (event.getShowEffect()) { -+ this.level().levelEvent(LevelEvent.PARTICLES_SPELL_POTION_SPLASH, this.blockPosition(), net.minecraft.world.item.alchemy.PotionContents.BASE_POTION_COLOR); ++ level.levelEvent(LevelEvent.PARTICLES_SPELL_POTION_SPLASH, this.blockPosition(), net.minecraft.world.item.alchemy.PotionContents.BASE_POTION_COLOR); + } + // Paper end - exp bottle event diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownLingeringPotion.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownLingeringPotion.java.patch index e41c58a29c49..3b32be385ff1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownLingeringPotion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownLingeringPotion.java.patch @@ -4,22 +4,22 @@ } @Override -- public void onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult) { -+ public boolean onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult) { // Paper - More projectile API - AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); - if (this.getOwner() instanceof LivingEntity livingEntity) { - areaEffectCloud.setOwner(livingEntity); +- public void onHitAsPotion(final ServerLevel level, final ItemStack potionItem, final HitResult hitResult) { ++ public boolean onHitAsPotion(final ServerLevel level, final ItemStack potionItem, final HitResult hitResult) { // Paper - More projectile API + AreaEffectCloud cloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); + if (this.getOwner() instanceof LivingEntity owner) { + cloud.setOwner(owner); @@ -41,6 +_,15 @@ - areaEffectCloud.setWaitTime(10); - areaEffectCloud.setRadiusPerTick(-areaEffectCloud.getRadius() / areaEffectCloud.getDuration()); - areaEffectCloud.applyComponentsFromItemStack(stack); + cloud.setWaitTime(10); + cloud.setRadiusPerTick(-cloud.getRadius() / cloud.getDuration()); + cloud.applyComponentsFromItemStack(potionItem); + boolean noEffects = this.getItem().getOrDefault(net.minecraft.core.component.DataComponents.POTION_CONTENTS, net.minecraft.world.item.alchemy.PotionContents.EMPTY).hasEffects(); // Paper - Fix potions splash events + // CraftBukkit start -+ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, hitResult, areaEffectCloud); -+ if (!(event.isCancelled() || areaEffectCloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !areaEffectCloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling - level.addFreshEntity(areaEffectCloud); ++ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, hitResult, cloud); ++ if (!(event.isCancelled() || cloud.isRemoved() || (!event.allowsEmptyCreation() && (noEffects && !cloud.potionContents.hasEffects())))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling + level.addFreshEntity(cloud); + } else { -+ areaEffectCloud.discard(null); ++ cloud.discard(null); + } + // CraftBukkit end + return !event.isCancelled(); // Paper - Fix potions splash events diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownSplashPotion.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownSplashPotion.java.patch index 5a1801fc2f15..8337f2feb8d1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownSplashPotion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownSplashPotion.java.patch @@ -4,52 +4,52 @@ } @Override -- public void onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult) { -+ public boolean onHitAsPotion(ServerLevel level, ItemStack stack, HitResult hitResult) { // Paper - More projectile API - PotionContents potionContents = stack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); - float orDefault = stack.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F); - Iterable allEffects = potionContents.getAllEffects(); - AABB aabb = this.getBoundingBox().move(hitResult.getLocation().subtract(this.position())); - AABB aabb1 = aabb.inflate(4.0, 2.0, 4.0); - List entitiesOfClass = this.level().getEntitiesOfClass(LivingEntity.class, aabb1); +- public void onHitAsPotion(final ServerLevel level, final ItemStack potionItem, final HitResult hitResult) { ++ public boolean onHitAsPotion(final ServerLevel level, final ItemStack potionItem, final HitResult hitResult) { // Paper - More projectile API + PotionContents contents = potionItem.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + float durationScale = potionItem.getOrDefault(DataComponents.POTION_DURATION_SCALE, 1.0F); + Iterable mobEffects = contents.getAllEffects(); + AABB potionAabb = this.getBoundingBox().move(hitResult.getLocation().subtract(this.position())); + AABB effectAabb = potionAabb.inflate(4.0, 2.0, 4.0); + List entities = this.level().getEntitiesOfClass(LivingEntity.class, effectAabb); + java.util.Map affected = new java.util.HashMap<>(); // CraftBukkit - float f = ProjectileUtil.computeMargin(this); - if (!entitiesOfClass.isEmpty()) { + float margin = ProjectileUtil.computeMargin(this); + if (!entities.isEmpty()) { Entity effectSource = this.getEffectSource(); @@ -52,8 +_,25 @@ - if (livingEntity.isAffectedByPotions()) { - double d = aabb.distanceToSqr(livingEntity.getBoundingBox().inflate(f)); - if (d < 16.0) { -- double d1 = 1.0 - Math.sqrt(d) / 4.0; + if (entity.isAffectedByPotions()) { + double dist = potionAabb.distanceToSqr(entity.getBoundingBox().inflate(margin)); + if (dist < 16.0) { +- double scale = 1.0 - Math.sqrt(dist) / 4.0; - -+ double d1 = 1.0 - Math.sqrt(d) / 4.0; // Paper - diff on change, used when calling the splash event for water splash potions ++ double scale = 1.0 - Math.sqrt(dist) / 4.0; // Paper - diff on change, used when calling the splash event for water splash potions + // CraftBukkit start -+ affected.put(livingEntity.getBukkitLivingEntity(), d1); ++ affected.put(entity.getBukkitLivingEntity(), scale); + } + } + } + } + org.bukkit.event.entity.PotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPotionSplashEvent(this, hitResult, affected); -+ if (!event.isCancelled() && !entitiesOfClass.isEmpty()) { // do not process effects if there are no effects to process ++ if (!event.isCancelled() && !entities.isEmpty()) { // do not process effects if there are no effects to process + Entity effectSource = this.getEffectSource(); + for (org.bukkit.entity.LivingEntity victim : event.getAffectedEntities()) { + if (!(victim instanceof org.bukkit.craftbukkit.entity.CraftLivingEntity craftLivingEntity)) { + continue; + } -+ LivingEntity livingEntity = craftLivingEntity.getHandle(); -+ double d1 = event.getIntensity(victim); ++ LivingEntity entity = craftLivingEntity.getHandle(); ++ double scale = event.getIntensity(victim); + { + { -+ // CraftBukkit end - for (MobEffectInstance mobEffectInstance : allEffects) { - Holder effect = mobEffectInstance.getEffect(); ++ // CraftBukkit end + for (MobEffectInstance effectInstance : mobEffects) { + Holder effect = effectInstance.getEffect(); if (effect.value().isInstantenous()) { @@ -64,7 +_,7 @@ - effect, i, mobEffectInstance.getAmplifier(), mobEffectInstance.isAmbient(), mobEffectInstance.isVisible() + effect, duration, effectInstance.getAmplifier(), effectInstance.isAmbient(), effectInstance.isVisible() ); - if (!mobEffectInstance1.endsWithin(20)) { -- livingEntity.addEffect(mobEffectInstance1, effectSource); -+ livingEntity.addEffect(mobEffectInstance1, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit + if (!newEffect.endsWithin(20)) { +- entity.addEffect(newEffect, effectSource); ++ entity.addEffect(newEffect, effectSource, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch index b5e70b6efac7..0258d237ed0b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/raid/Raid.java +++ b/net/minecraft/world/entity/raid/Raid.java -@@ -61,6 +_,12 @@ +@@ -63,6 +_,12 @@ import org.jspecify.annotations.Nullable; public class Raid { @@ -12,17 +12,17 @@ + // Paper end public static final SpawnPlacementType RAVAGER_SPAWN_PLACEMENT_TYPE = SpawnPlacements.getPlacementType(EntityType.RAVAGER); public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( -@@ -76,6 +_,8 @@ - Raid.RaidStatus.CODEC.fieldOf("status").forGetter(raid -> raid.status), - BlockPos.CODEC.fieldOf("center").forGetter(raid -> raid.center), - UUIDUtil.CODEC_SET.fieldOf("heroes_of_the_village").forGetter(raid -> raid.heroesOfTheVillage) + i -> i.group( +@@ -78,6 +_,8 @@ + Raid.RaidStatus.CODEC.fieldOf("status").forGetter(r -> r.status), + BlockPos.CODEC.fieldOf("center").forGetter(r -> r.center), + UUIDUtil.CODEC_SET.fieldOf("heroes_of_the_village").forGetter(r -> r.heroesOfTheVillage) + , org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer.createCodec(PDC_TYPE_REGISTRY).lenientOptionalFieldOf(PDC_NBT_KEY) // Paper - add persistent data container + .forGetter(raid -> raid.persistentDataContainer.isEmpty() ? java.util.Optional.empty() : java.util.Optional.of(raid.persistentDataContainer)) // Paper - add persistent data container ) - .apply(instance, Raid::new) + .apply(i, Raid::new) ); -@@ -127,6 +_,7 @@ +@@ -131,6 +_,7 @@ this.center = center; this.numGroups = this.getNumGroups(difficulty); this.status = Raid.RaidStatus.ONGOING; @@ -30,15 +30,15 @@ } private Raid( -@@ -142,6 +_,7 @@ - Raid.RaidStatus status, - BlockPos center, - Set heroesOfTheVillage +@@ -146,6 +_,7 @@ + final Raid.RaidStatus status, + final BlockPos center, + final Set heroesOfTheVillage + , final Optional persistentDataContainer // Paper - add persistent data container ) { this.started = started; this.active = active; -@@ -155,6 +_,7 @@ +@@ -159,6 +_,7 @@ this.numGroups = numGroups; this.status = status; this.heroesOfTheVillage.addAll(heroesOfTheVillage); @@ -46,7 +46,7 @@ } public boolean isOver() { -@@ -181,6 +_,12 @@ +@@ -185,6 +_,12 @@ return this.status == Raid.RaidStatus.LOSS; } @@ -59,15 +59,15 @@ public float getTotalHealth() { return this.totalHealth; } -@@ -267,6 +_,7 @@ - boolean flag = this.active; +@@ -271,6 +_,7 @@ + boolean oldActive = this.active; this.active = level.hasChunkAt(this.center); if (level.getDifficulty() == Difficulty.PEACEFUL) { + org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.PEACE); // CraftBukkit this.stop(); return; } -@@ -286,13 +_,16 @@ +@@ -290,13 +_,16 @@ if (!level.isVillage(this.center)) { if (this.groupsSpawned > 0) { this.status = Raid.RaidStatus.LOSS; @@ -84,27 +84,27 @@ this.stop(); return; } -@@ -381,6 +_,7 @@ +@@ -385,6 +_,7 @@ } - if (i > 5) { + if (attempt > 5) { + org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit this.stop(); break; } -@@ -392,6 +_,7 @@ +@@ -396,6 +_,7 @@ } else { this.status = Raid.RaidStatus.VICTORY; + List winners = new java.util.ArrayList<>(); // CraftBukkit - for (UUID uuid : this.heroesOfTheVillage) { - Entity entity = level.getEntity(uuid); - if (entity instanceof LivingEntity livingEntity && !entity.isSpectator()) { -@@ -399,9 +_,11 @@ - if (livingEntity instanceof ServerPlayer serverPlayer) { - serverPlayer.awardStat(Stats.RAID_WIN); - CriteriaTriggers.RAID_WIN.trigger(serverPlayer); -+ winners.add(serverPlayer.getBukkitEntity()); // CraftBukkit + for (UUID heroUUID : this.heroesOfTheVillage) { + Entity entity = level.getEntity(heroUUID); + if (entity instanceof LivingEntity hero && !entity.isSpectator()) { +@@ -403,9 +_,11 @@ + if (hero instanceof ServerPlayer playerHero) { + playerHero.awardStat(Stats.RAID_WIN); + CriteriaTriggers.RAID_WIN.trigger(playerHero); ++ winners.add(playerHero.getBukkitEntity()); // CraftBukkit } } } @@ -112,7 +112,7 @@ } } -@@ -409,6 +_,7 @@ +@@ -413,6 +_,7 @@ } else if (this.isOver()) { this.celebrationTicks++; if (this.celebrationTicks >= 600) { @@ -120,35 +120,26 @@ this.stop(); return; } -@@ -513,7 +_,7 @@ - - private void spawnGroup(ServerLevel level, BlockPos pos) { - boolean flag = false; -- int i = this.groupsSpawned + 1; -+ int i = this.groupsSpawned + 1; final int wave = i; // Paper - OBFHELPER - this.totalHealth = 0.0F; - DifficultyInstance currentDifficultyAt = level.getCurrentDifficultyAt(pos); - boolean shouldSpawnBonusGroup = this.shouldSpawnBonusGroup(); -@@ -562,6 +_,7 @@ +@@ -568,6 +_,7 @@ this.groupsSpawned++; this.updateBossbar(); this.setDirty(level); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callRaidSpawnWaveEvent(level, this, java.util.Objects.requireNonNull(this.getLeader(wave)), this.groupRaiderMap.get(wave)); // CraftBukkit ++ org.bukkit.craftbukkit.event.CraftEventFactory.callRaidSpawnWaveEvent(level, this, java.util.Objects.requireNonNull(this.getLeader(groupNumber)), this.groupRaiderMap.get(groupNumber)); // CraftBukkit } - public void joinRaid(ServerLevel level, int wave, Raider raider, @Nullable BlockPos pos, boolean isRecruited) { -@@ -576,7 +_,7 @@ + public void joinRaid(final ServerLevel level, final int groupNumber, final Raider raider, final @Nullable BlockPos pos, final boolean exists) { +@@ -582,7 +_,7 @@ raider.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.EVENT, null); - raider.applyRaidBuffs(level, wave, false); + raider.applyRaidBuffs(level, groupNumber, false); raider.setOnGround(true); - level.addFreshEntityWithPassengers(raider); + level.addFreshEntityWithPassengers(raider, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.RAID); // CraftBukkit } } } -@@ -793,6 +_,12 @@ - public void addHeroOfTheVillage(Entity player) { - this.heroesOfTheVillage.add(player.getUUID()); +@@ -809,6 +_,12 @@ + public void addHeroOfTheVillage(final Entity killer) { + this.heroesOfTheVillage.add(killer.getUUID()); } + + // CraftBukkit start - a method to get all raiders @@ -157,5 +148,5 @@ + } + // CraftBukkit end - static enum RaidStatus implements StringRepresentable { + private static enum RaidStatus implements StringRepresentable { ONGOING("ongoing"), diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch index e71cc3849ea2..4e8e0ac92a21 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch @@ -2,25 +2,25 @@ +++ b/net/minecraft/world/entity/raid/Raider.java @@ -212,17 +_,24 @@ if (this.hasActiveRaid() - && !flag - && ItemStack.matches(item, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { + && !hasRaidLeader + && ItemStack.matches(itemStack, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { + // Paper start - EntityPickupItemEvent fixes + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0).isCancelled()) { + return; + } + // Paper end - EntityPickupItemEvent fixes - EquipmentSlot equipmentSlot = EquipmentSlot.HEAD; - ItemStack itemBySlot = this.getItemBySlot(equipmentSlot); - double d = this.getDropChances().byEquipment(equipmentSlot); - if (!itemBySlot.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d) { + EquipmentSlot slot = EquipmentSlot.HEAD; + ItemStack current = this.getItemBySlot(slot); + double dropChance = this.getDropChances().byEquipment(slot); + if (!current.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < dropChance) { + this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.spawnAtLocation(level, itemBySlot); + this.spawnAtLocation(level, current); + this.forceDrops = false; // Paper - Add missing forceDrop toggles } this.onItemPickup(entity); - this.setItemSlot(equipmentSlot, item); - this.take(entity, item.getCount()); + this.setItemSlot(slot, itemStack); + this.take(entity, itemStack.getCount()); - entity.discard(); + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause this.getCurrentRaid().setLeader(this.getWave(), this); @@ -28,23 +28,23 @@ } else { @@ -295,7 +_,7 @@ - for (Raider raider : getServerLevel(this.mob) + for (Raider entity : getServerLevel(this.mob) .getNearbyEntities(Raider.class, this.shoutTargeting, this.mob, this.mob.getBoundingBox().inflate(8.0, 8.0, 8.0))) { -- raider.setTarget(this.mob.getTarget()); -+ raider.setTarget(this.mob.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); // CraftBukkit +- entity.setTarget(this.mob.getTarget()); ++ entity.setTarget(this.mob.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); // CraftBukkit } } @@ -306,7 +_,7 @@ if (target != null) { - for (Raider raider : getServerLevel(this.mob) + for (Raider entity : getServerLevel(this.mob) .getNearbyEntities(Raider.class, this.shoutTargeting, this.mob, this.mob.getBoundingBox().inflate(8.0, 8.0, 8.0))) { -- raider.setTarget(target); -+ raider.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); // CraftBukkit - raider.setAggressive(true); +- entity.setTarget(target); ++ entity.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER); // CraftBukkit + entity.setAggressive(true); } -@@ -389,6 +_,7 @@ +@@ -392,6 +_,7 @@ } private boolean cannotPickUpBanner() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch index 0efe66607e7e..64840baa8750 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/entity/raid/Raids.java +++ b/net/minecraft/world/entity/raid/Raids.java -@@ -59,6 +_,7 @@ - private Raids(List raids, int nextId, int tick) { - for (Raids.RaidWithId raidWithId : raids) { - this.raidMap.put(raidWithId.id, raidWithId.raid); -+ raidWithId.raid.idOrNegativeOne = raidWithId.id; // Paper - expose id of raids while method is kept around as deprecated for removal +@@ -52,6 +_,7 @@ + private Raids(final List raids, final int nextId, final int tick) { + for (Raids.RaidWithId raid : raids) { + this.raidMap.put(raid.id, raid.raid); ++ raid.raid.idOrNegativeOne = raid.id; // Paper - expose id of raids while method is kept around as deprecated for removal } this.nextId = nextId; -@@ -137,11 +_,23 @@ +@@ -130,11 +_,23 @@ } - Raid raid = this.getOrCreateRaid(serverLevel, blockPos); + Raid raid = this.getOrCreateRaid(level, raidCenterPos); - if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { - this.raidMap.put(this.getUniqueId(), raid); - } @@ -24,7 +24,7 @@ + + if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(serverLevel, raid, player)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(level, raid, player)) { + player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); + return null; + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/variant/StructureCheck.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/variant/StructureCheck.java.patch index fea326d418df..e48b77c0e873 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/variant/StructureCheck.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/variant/StructureCheck.java.patch @@ -3,7 +3,7 @@ @@ -15,7 +_,7 @@ @Override - public boolean test(SpawnContext context) { + public boolean test(final SpawnContext context) { - return context.level().getLevel().structureManager().getStructureWithPieceAt(context.pos(), this.requiredStructures).isValid(); + return context.level().getLevel().structureManager().getStructureWithPieceAt(context.pos(), this.requiredStructures, context.level()).isValid(); // Paper - Fix swamp hut cat generation deadlock } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch index ceb95d1af909..4ec5f3460b32 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/vehicle/ContainerEntity.java +++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java @@ -59,12 +_,12 @@ - default void addChestVehicleSaveData(ValueOutput output) { + default void addChestVehicleSaveData(final ValueOutput output) { if (this.getContainerLootTable() != null) { output.putString("LootTable", this.getContainerLootTable().identifier().toString()); + this.lootableData().saveNbt(output); // Paper @@ -14,25 +14,25 @@ + ContainerHelper.saveAllItems(output, this.getItemStacks()); // Paper - always save the items, table may still remain } - default void readChestVehicleSaveData(ValueInput input) { + default void readChestVehicleSaveData(final ValueInput input) { @@ -72,7 +_,12 @@ - ResourceKey resourceKey = input.read("LootTable", LootTable.KEY_CODEC).orElse(null); - this.setContainerLootTable(resourceKey); + ResourceKey lootTable = input.read("LootTable", LootTable.KEY_CODEC).orElse(null); + this.setContainerLootTable(lootTable); this.setContainerLootTableSeed(input.getLongOr("LootTableSeed", 0L)); -- if (resourceKey == null) { +- if (lootTable == null) { + // Paper start - LootTable API + if (this.getContainerLootTable() != null) { + this.lootableData().loadNbt(input); + } + // Paper end - LootTable API -+ if (true || resourceKey == null) { // Paper - always read the items, table may still remain ++ if (true || lootTable == null) { // Paper - always read the items, table may still remain ContainerHelper.loadAllItems(input, this.getItemStacks()); } } -@@ -88,19 +_,27 @@ +@@ -87,19 +_,27 @@ } - default InteractionResult interactWithContainerVehicle(Player player) { + default InteractionResult interactWithContainerVehicle(final Player player) { - player.openMenu(this); + // Paper start - Fix InventoryOpenEvent cancellation + if (player.openMenu(this).isEmpty()) { @@ -42,7 +42,7 @@ return InteractionResult.SUCCESS; } - default void unpackChestVehicleLootTable(@Nullable Player player) { + default void unpackChestVehicleLootTable(final @Nullable Player player) { MinecraftServer server = this.level().getServer(); - if (this.getContainerLootTable() != null && server != null) { + if (server != null && this.lootableData().shouldReplenish(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.ENTITY, player)) { // Paper - LootTable API @@ -60,8 +60,8 @@ LootParams.Builder builder = new LootParams.Builder((ServerLevel)this.level()).withParameter(LootContextParams.ORIGIN, this.position()); if (player != null) { builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player); -@@ -170,4 +_,14 @@ - default boolean isChestVehicleStillValid(Player player) { +@@ -173,4 +_,14 @@ + default boolean isChestVehicleStillValid(final Player player) { return !this.isRemoved() && player.isWithinEntityInteractionRange(this.getBoundingBox(), 4.0); } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch index 0020b09f5192..70c89728a761 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch @@ -1,24 +1,31 @@ --- a/net/minecraft/world/entity/vehicle/VehicleEntity.java +++ b/net/minecraft/world/entity/vehicle/VehicleEntity.java -@@ -38,6 +_,14 @@ - } else if (this.isInvulnerableToBase(damageSource)) { +@@ -32,12 +_,20 @@ + } + + @Override +- public boolean hurtServer(final ServerLevel level, final DamageSource source, final float damage) { ++ public boolean hurtServer(final ServerLevel level, final DamageSource source, float damage) { // Paper - unfinal damage + if (this.isRemoved()) { + return true; + } else if (this.isInvulnerableToBase(source)) { return false; } else { + // CraftBukkit start + org.bukkit.entity.Vehicle vehicle = (org.bukkit.entity.Vehicle) this.getBukkitEntity(); -+ org.bukkit.entity.Entity attacker = (damageSource.getEntity() == null) ? null : damageSource.getEntity().getBukkitEntity(); ++ org.bukkit.entity.Entity attacker = (source.getEntity() == null) ? null : source.getEntity().getBukkitEntity(); + -+ org.bukkit.event.vehicle.VehicleDamageEvent event = new org.bukkit.event.vehicle.VehicleDamageEvent(vehicle, attacker, amount); ++ org.bukkit.event.vehicle.VehicleDamageEvent event = new org.bukkit.event.vehicle.VehicleDamageEvent(vehicle, attacker, damage); + if (!event.callEvent()) return false; -+ amount = (float) event.getDamage(); ++ damage = (float) event.getDamage(); + // CraftBukkit end this.setHurtDir(-this.getHurtDir()); this.setHurtTime(10); this.markHurt(); @@ -46,9 +_,23 @@ - boolean flag = damageSource.getEntity() instanceof Player player && player.getAbilities().instabuild; - if ((flag || !(this.getDamage() > 40.0F)) && !this.shouldSourceDestroy(damageSource)) { - if (flag) { + boolean creativePlayer = source.getEntity() instanceof Player player && player.getAbilities().instabuild; + if ((creativePlayer || !(this.getDamage() > 40.0F)) && !this.shouldSourceDestroy(source)) { + if (creativePlayer) { - this.discard(); + // CraftBukkit start + org.bukkit.event.vehicle.VehicleDestroyEvent destroyEvent = new org.bukkit.event.vehicle.VehicleDestroyEvent(vehicle, attacker); @@ -37,6 +44,6 @@ + return true; + } + // CraftBukkit end - this.destroy(level, damageSource); + this.destroy(level, source); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch index c26b465f5514..de8104e621bd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch @@ -13,7 +13,7 @@ + private org.bukkit.Location lastLocation; + // CraftBukkit end + - public AbstractBoat(EntityType type, Level level, Supplier dropItem) { + public AbstractBoat(final EntityType type, final Level level, final Supplier dropItem) { super(type, level); this.dropItem = dropItem; @@ -120,7 +_,7 @@ @@ -28,7 +28,7 @@ @@ -175,11 +_,30 @@ @Override - public void push(Entity entity) { + public void push(final Entity entity) { + if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant if (entity instanceof AbstractBoat) { if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) { @@ -75,12 +75,12 @@ this.applyEffectsFromBlocks(); this.applyEffectsFromBlocks(); this.tickBubbleColumn(); -@@ -545,7 +_,7 @@ +@@ -543,7 +_,7 @@ this.waterLevel = this.getY(1.0); - double d2 = this.getWaterLevelAbove() - this.getBbHeight() + 0.101; - if (this.level().noCollision(this, this.getBoundingBox().move(0.0, d2 - this.getY(), 0.0))) { -- this.setPos(this.getX(), d2, this.getZ()); -+ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Fix some exploit with boats // TODO Still needed? + double targetY = this.getWaterLevelAbove() - this.getBbHeight() + 0.101; + if (this.level().noCollision(this, this.getBoundingBox().move(0.0, targetY - this.getY(), 0.0))) { +- this.setPos(this.getX(), targetY, this.getZ()); ++ this.move(MoverType.SELF, new Vec3(0.0, targetY - this.getY(), 0.0)); // Paper - Fix some exploit with boats // TODO Still needed? this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.0, 1.0)); this.lastYd = 0.0; } @@ -88,8 +88,8 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause if (!this.level().isClientSide() && reason.shouldDestroy() && this.isLeashed()) { this.dropLeash(); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch index fe519a27e621..67ecbf491eed 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java +++ b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java -@@ -67,12 +_,12 @@ +@@ -68,12 +_,12 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause if (!this.level().isClientSide() && reason.shouldDestroy()) { Containers.dropContents(this.level(), this, this); } @@ -15,29 +15,29 @@ } @Override -@@ -95,8 +_,8 @@ +@@ -96,8 +_,8 @@ @Override - public void openCustomInventoryScreen(Player player) { + public void openCustomInventoryScreen(final Player player) { - player.openMenu(this); -- if (player.level() instanceof ServerLevel serverLevel) { +- if (player.level() instanceof ServerLevel level) { + // Paper - fix inventory open cancel - moved into below if -+ if (player.level() instanceof ServerLevel serverLevel && player.openMenu(this).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation ++ if (player.level() instanceof ServerLevel level && player.openMenu(this).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation this.gameEvent(GameEvent.CONTAINER_OPEN, player); - PiglinAi.angerNearbyPiglins(serverLevel, player, true); + PiglinAi.angerNearbyPiglins(level, player, true); } -@@ -148,7 +_,7 @@ +@@ -149,7 +_,7 @@ @Override - public @Nullable AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { + public @Nullable AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { - if (this.lootTable != null && player.isSpectator()) { + if (this.lootTable != null && player.isSpectator()) { // Paper - LootTable API (TODO spectators can open chests that aren't ready to be re-generated but this doesn't support that) return null; } else { - this.unpackLootTable(playerInventory.player); -@@ -194,4 +_,58 @@ - public void stopOpen(ContainerUser user) { - this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of(user.getLivingEntity())); + this.unpackLootTable(inventory.player); +@@ -195,4 +_,58 @@ + public void stopOpen(final ContainerUser containerUser) { + this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of(containerUser.getLivingEntity())); } + + // Paper start - LootTable API diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java.patch index 3e918e368e71..3cb5b2ff19bc 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java.patch @@ -16,12 +16,12 @@ + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + // CraftBukkit end - protected AbstractMinecart(EntityType type, Level level) { + protected AbstractMinecart(final EntityType type, final Level level) { super(type, level); -@@ -154,11 +_,19 @@ +@@ -161,11 +_,19 @@ @Override - public boolean canCollideWith(Entity entity) { + public boolean canCollideWith(final Entity entity) { - return AbstractBoat.canVehicleCollide(this, entity); + // Paper start - fix VehicleEntityCollisionEvent not called when colliding with player + boolean collides = AbstractBoat.canVehicleCollide(this, entity); @@ -40,7 +40,7 @@ return true; } -@@ -259,6 +_,14 @@ +@@ -270,6 +_,14 @@ @Override public void tick() { @@ -55,7 +55,7 @@ if (this.getHurtTime() > 0) { this.setHurtTime(this.getHurtTime() - 1); } -@@ -269,8 +_,20 @@ +@@ -280,8 +_,20 @@ this.checkBelowWorld(); this.computeSpeed(); @@ -74,12 +74,12 @@ + new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, from, to).callEvent(); + } + // CraftBukkit end - this.updateInWaterStateAndDoFluidPushing(); + this.updateFluidInteraction(); if (this.isInLava()) { this.lavaIgnite(); -@@ -358,12 +_,16 @@ - Vec3 deltaMovement = this.getDeltaMovement(); - this.setDeltaMovement(Mth.clamp(deltaMovement.x, -maxSpeed, maxSpeed), deltaMovement.y, Mth.clamp(deltaMovement.z, -maxSpeed, maxSpeed)); +@@ -371,12 +_,16 @@ + Vec3 movement = this.getDeltaMovement(); + this.setDeltaMovement(Mth.clamp(movement.x, -maxSpeed, maxSpeed), movement.y, Mth.clamp(movement.z, -maxSpeed, maxSpeed)); if (this.onGround()) { - this.setDeltaMovement(this.getDeltaMovement().scale(0.5)); + // CraftBukkit start - replace magic numbers with our variables @@ -96,7 +96,7 @@ } } -@@ -465,6 +_,15 @@ +@@ -478,6 +_,15 @@ this.setDisplayOffset(input.getIntOr("DisplayOffset", this.getDefaultDisplayOffset())); this.flipped = input.getBooleanOr("FlippedRotation", false); this.firstTick = input.getBooleanOr("HasTicked", false); @@ -112,7 +112,7 @@ } @Override -@@ -477,13 +_,26 @@ +@@ -490,13 +_,26 @@ output.putBoolean("FlippedRotation", this.flipped); output.putBoolean("HasTicked", this.firstTick); @@ -124,7 +124,7 @@ } @Override - public void push(Entity entity) { + public void push(final Entity entity) { if (!this.level().isClientSide()) { if (!entity.noPhysics && !this.noPhysics) { + if (!this.level().paperConfig().collisions.allowVehicleCollisions && this.level().paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper - Collision option for requiring a player participant @@ -136,10 +136,10 @@ + ); + if (!collisionEvent.callEvent()) return; + // CraftBukkit end - double d = entity.getX() - this.getX(); - double d1 = entity.getZ() - this.getZ(); - double d2 = d * d + d1 * d1; -@@ -592,4 +_,26 @@ + double xa = entity.getX() - this.getX(); + double za = entity.getZ() - this.getZ(); + double dd = xa * xa + za * za; +@@ -605,4 +_,26 @@ public boolean isFurnace() { return false; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java.patch index aef9f3d9e99e..c6e97e427dcc 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java.patch @@ -10,14 +10,14 @@ public long lootTableSeed; + private final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(); // Paper - LootTable API - protected AbstractMinecartContainer(EntityType type, Level level) { + protected AbstractMinecartContainer(final EntityType type, final Level level) { super(type, level); @@ -72,12 +_,12 @@ } @Override -- public void remove(Entity.RemovalReason reason) { -+ public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause +- public void remove(final Entity.RemovalReason reason) { ++ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause if (!this.level().isClientSide() && reason.shouldDestroy()) { Containers.dropContents(this.level(), this, this); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch index 0eaa33118f97..b90a4b0a86c3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java +++ b/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java -@@ -84,7 +_,7 @@ +@@ -88,7 +_,7 @@ @Override - public InteractionResult interact(Player player, InteractionHand hand) { + public InteractionResult interact(final Player player, final InteractionHand hand, final Vec3 location) { - if (!player.canUseGameMasterBlocks()) { + if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission return InteractionResult.PASS; } else { if (player.level().isClientSide()) { -@@ -122,7 +_,7 @@ +@@ -131,7 +_,7 @@ MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), level, @@ -18,7 +18,7 @@ this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), level.getServer(), -@@ -134,5 +_,17 @@ +@@ -143,5 +_,17 @@ public boolean isValid() { return !MinecartCommandBlock.this.isRemoved(); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java.patch index a0cc24069497..228857bf91fd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java +++ b/net/minecraft/world/entity/vehicle/minecart/MinecartTNT.java -@@ -39,6 +_,7 @@ +@@ -38,6 +_,7 @@ public int fuse = -1; public float explosionPowerBase = 4.0F; public float explosionSpeedFactor = 1.0F; + public boolean isIncendiary = false; // CraftBukkit - public MinecartTNT(EntityType type, Level level) { + public MinecartTNT(final EntityType type, final Level level) { super(type, level); -@@ -53,6 +_,12 @@ +@@ -52,6 +_,12 @@ public void tick() { super.tick(); if (this.fuse > 0) { @@ -21,14 +21,14 @@ this.fuse--; this.level().addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5, this.getZ(), 0.0, 0.0, 0.0); } else if (this.fuse == 0) { -@@ -104,6 +_,17 @@ - if (this.level() instanceof ServerLevel serverLevel) { - if (serverLevel.getGameRules().get(GameRules.TNT_EXPLODES)) { - double min = Math.min(Math.sqrt(radiusModifier), 5.0); +@@ -103,6 +_,17 @@ + if (this.level() instanceof ServerLevel level) { + if (level.getGameRules().get(GameRules.TNT_EXPLODES)) { + double speed = Math.min(Math.sqrt(speedSqr), 5.0); + // CraftBukkit start + org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent( + this.getBukkitEntity(), -+ (float) (this.explosionPowerBase + this.explosionSpeedFactor * this.random.nextDouble() * 1.5 * min), ++ (float) (this.explosionPowerBase + this.explosionSpeedFactor * this.random.nextDouble() * 1.5 * speed), + this.isIncendiary + ); + if (!event.callEvent()) { @@ -36,14 +36,14 @@ + return; + } + // CraftBukkit end - serverLevel.explode( + level.explode( this, damageSource, -@@ -111,13 +_,13 @@ +@@ -110,13 +_,13 @@ this.getX(), this.getY(), this.getZ(), -- (float)(this.explosionPowerBase + this.explosionSpeedFactor * this.random.nextDouble() * 1.5 * min), +- (float)(this.explosionPowerBase + this.explosionSpeedFactor * this.random.nextDouble() * 1.5 * speed), - false, + event.getRadius(), // CraftBukkit - explosion prime event + event.getFire(), // CraftBukkit - explosion prime event diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch index d07d507f6177..bbf4cca13b12 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java +++ b/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java -@@ -479,6 +_,12 @@ +@@ -482,6 +_,12 @@ @Override - public double getMaxSpeed(ServerLevel level) { + public double getMaxSpeed(final ServerLevel level) { + // CraftBukkit start + Double maxSpeed = this.minecart.maxSpeed; + if (maxSpeed != null) { -+ return this.minecart.isInWater() ? maxSpeed / 2.0D : maxSpeed; ++ return this.minecart.isInWater() ? maxSpeed / 2.0 : maxSpeed; + } + // CraftBukkit end return level.getGameRules().get(GameRules.MAX_MINECART_SPEED).intValue() * (this.minecart.isInWater() ? 0.5 : 1.0) / 20.0; } -@@ -494,7 +_,8 @@ +@@ -497,7 +_,8 @@ @Override public double getSlowdownFactor() { @@ -23,7 +23,7 @@ } @Override -@@ -518,6 +_,13 @@ +@@ -521,6 +_,13 @@ && !(entity instanceof AbstractMinecart) && !this.minecart.isVehicle() && !entity.isPassenger()) { @@ -34,10 +34,10 @@ + ); + if (!collisionEvent.callEvent()) continue; + // CraftBukkit end - boolean flag = entity.startRiding(this.minecart); - if (flag) { + boolean pickedUp = entity.startRiding(this.minecart); + if (pickedUp) { return true; -@@ -541,6 +_,17 @@ +@@ -544,6 +_,17 @@ || entity instanceof AbstractMinecart || this.minecart.isVehicle() || entity.isPassenger()) { @@ -53,21 +53,21 @@ + } + // CraftBukkit end entity.push(this.minecart); - flag = true; + pushed = true; } -@@ -549,6 +_,15 @@ +@@ -552,6 +_,15 @@ } else { - for (Entity entity1 : this.level().getEntities(this.minecart, box)) { - if (!this.minecart.hasPassenger(entity1) && entity1.isPushable() && entity1 instanceof AbstractMinecart) { + for (Entity entityx : this.level().getEntities(this.minecart, hitbox)) { + if (!this.minecart.hasPassenger(entityx) && entityx.isPushable() && entityx instanceof AbstractMinecart) { + // CraftBukkit start + org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent( + (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), -+ entity1.getBukkitEntity() ++ entityx.getBukkitEntity() + ); + if (!collisionEvent.callEvent()) { + continue; + } + // CraftBukkit end - entity1.push(this.minecart); - flag = true; + entityx.push(this.minecart); + pushed = true; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch index e4369eabbed7..891b315c2eb6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java +++ b/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java -@@ -376,8 +_,22 @@ +@@ -375,8 +_,22 @@ && !(entity instanceof AbstractMinecart) && !this.minecart.isVehicle() && !entity.isPassenger()) { @@ -23,27 +23,27 @@ entity.push(this.minecart); } } -@@ -385,6 +_,12 @@ +@@ -384,6 +_,12 @@ } else { - for (Entity entity1 : this.level().getEntities(this.minecart, aabb)) { - if (!this.minecart.hasPassenger(entity1) && entity1.isPushable() && entity1 instanceof AbstractMinecart) { + for (Entity entityx : this.level().getEntities(this.minecart, hitbox)) { + if (!this.minecart.hasPassenger(entityx) && entityx.isPushable() && entityx instanceof AbstractMinecart) { + // CraftBukkit start + org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent( -+ (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), entity1.getBukkitEntity() ++ (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), entityx.getBukkitEntity() + ); + if (!collisionEvent.callEvent()) continue; + // CraftBukkit end - entity1.push(this.minecart); + entityx.push(this.minecart); } } -@@ -407,11 +_,18 @@ +@@ -406,11 +_,18 @@ @Override - public double getMaxSpeed(ServerLevel level) { + public double getMaxSpeed(final ServerLevel level) { + // CraftBukkit start + Double maxSpeed = this.minecart.maxSpeed; + if (maxSpeed != null) { -+ return this.minecart.isInWater() ? maxSpeed / 2.0D : maxSpeed; ++ return this.minecart.isInWater() ? maxSpeed / 2.0 : maxSpeed; + } + // CraftBukkit end return this.minecart.isInWater() ? 0.2 : 0.4; diff --git a/paper-server/patches/sources/net/minecraft/world/food/FoodData.java.patch b/paper-server/patches/sources/net/minecraft/world/food/FoodData.java.patch index 4b595cfd1806..1b22a9dfeda4 100644 --- a/paper-server/patches/sources/net/minecraft/world/food/FoodData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/food/FoodData.java.patch @@ -10,8 +10,8 @@ + public int starvationRate = 80; + // CraftBukkit end - private void add(int nutrition, float saturationLevel) { - this.foodLevel = Mth.clamp(nutrition + this.foodLevel, 0, 20); + private void add(final int food, final float saturation) { + this.foodLevel = Mth.clamp(food + this.foodLevel, 0, 20); @@ -29,6 +_,17 @@ this.add(foodProperties.nutrition(), foodProperties.saturation()); } @@ -27,9 +27,9 @@ + } + // CraftBukkit end + - public void tick(ServerPlayer player) { - ServerLevel serverLevel = player.level(); - Difficulty difficulty = serverLevel.getDifficulty(); + public void tick(final ServerPlayer player) { + ServerLevel level = player.level(); + Difficulty difficulty = level.getDifficulty(); @@ -37,29 +_,39 @@ if (this.saturationLevel > 0.0F) { this.saturationLevel = Math.max(this.saturationLevel - 1.0F, 0.0F); @@ -47,27 +47,27 @@ } } - boolean flag = serverLevel.getGameRules().get(GameRules.NATURAL_HEALTH_REGENERATION); - if (flag && this.saturationLevel > 0.0F && player.isHurt() && this.foodLevel >= 20) { + boolean naturalRegen = level.getGameRules().get(GameRules.NATURAL_HEALTH_REGENERATION); + if (naturalRegen && this.saturationLevel > 0.0F && player.isHurt() && this.foodLevel >= 20) { this.tickTimer++; - if (this.tickTimer >= 10) { + if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit - float min = Math.min(this.saturationLevel, 6.0F); -- player.heal(min / 6.0F); -- this.addExhaustion(min); -+ player.heal(min / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen -+ // this.addExhaustion(min); CraftBukkit - EntityExhaustionEvent -+ player.causeFoodExhaustion(min, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent + float saturationSpent = Math.min(this.saturationLevel, 6.0F); +- player.heal(saturationSpent / 6.0F); +- this.addExhaustion(saturationSpent); ++ player.heal(saturationSpent / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen ++ // this.addExhaustion(saturationSpent); // CraftBukkit - EntityExhaustionEvent ++ player.causeFoodExhaustion(saturationSpent, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent this.tickTimer = 0; } - } else if (flag && this.foodLevel >= 18 && player.isHurt()) { + } else if (naturalRegen && this.foodLevel >= 18 && player.isHurt()) { this.tickTimer++; - if (this.tickTimer >= 80) { - player.heal(1.0F); - this.addExhaustion(6.0F); + if (this.tickTimer >= this.unsaturatedRegenRate) { // CraftBukkit - add regen rate manipulation + player.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason -+ // this.addExhaustion(6.0F); CraftBukkit - EntityExhaustionEvent ++ // this.addExhaustion(6.0F); // CraftBukkit - EntityExhaustionEvent + player.causeFoodExhaustion(player.level().spigotConfig.regenExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value this.tickTimer = 0; } @@ -76,5 +76,5 @@ - if (this.tickTimer >= 80) { + if (this.tickTimer >= this.starvationRate) { // CraftBukkit - add regen rate manipulation if (player.getHealth() > 10.0F || difficulty == Difficulty.HARD || player.getHealth() > 1.0F && difficulty == Difficulty.NORMAL) { - player.hurtServer(serverLevel, player.damageSources().starve(), 1.0F); + player.hurtServer(level, player.damageSources().starve(), 1.0F); } diff --git a/paper-server/patches/sources/net/minecraft/world/food/FoodProperties.java.patch b/paper-server/patches/sources/net/minecraft/world/food/FoodProperties.java.patch index d6ade19bb431..a6b6de13f333 100644 --- a/paper-server/patches/sources/net/minecraft/world/food/FoodProperties.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/food/FoodProperties.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/food/FoodProperties.java +++ b/net/minecraft/world/food/FoodProperties.java @@ -41,7 +_,7 @@ - RandomSource random = entity.getRandom(); - level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), consumable.sound().value(), SoundSource.NEUTRAL, 1.0F, random.triangle(1.0F, 0.4F)); - if (entity instanceof Player player) { + RandomSource random = user.getRandom(); + level.playSound(null, user.getX(), user.getY(), user.getZ(), consumable.sound().value(), SoundSource.NEUTRAL, 1.0F, random.triangle(1.0F, 0.4F)); + if (user instanceof Player player) { - player.getFoodData().eat(this); + player.getFoodData().eat(this, stack, (net.minecraft.server.level.ServerPlayer) player); // CraftBukkit level.playSound( diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch index 37c974a48096..f412b899e742 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/AbstractContainerMenu.java +++ b/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -63,6 +_,35 @@ +@@ -64,6 +_,35 @@ private final List containerListeners = Lists.newArrayList(); private @Nullable ContainerSynchronizer synchronizer; private boolean suppressRemoteUpdates; @@ -34,12 +34,12 @@ + public void startOpen() {} + // CraftBukkit end - protected AbstractContainerMenu(@Nullable MenuType menuType, int containerId) { + protected AbstractContainerMenu(final @Nullable MenuType menuType, final int containerId) { this.menuType = menuType; -@@ -174,8 +_,43 @@ +@@ -175,8 +_,43 @@ if (this.synchronizer != null) { - this.synchronizer.sendInitialData(this, list, carried.copy(), this.remoteDataSlots.toIntArray()); + this.synchronizer.sendInitialData(this, itemsToSend, carried.copy(), this.remoteDataSlots.toIntArray()); - } - } + this.synchronizer.sendOffHandSlotChange(); // Paper - Sync offhand slot in menus; update player's offhand since the offhand slot is not added to the slots for menus but can be changed by swapping from a menu slot @@ -80,52 +80,52 @@ + } + // CraftBukkit end - public void removeSlotListener(ContainerListener listener) { + public void removeSlotListener(final ContainerListener listener) { this.containerListeners.remove(listener); -@@ -241,7 +_,7 @@ - this.lastSlots.set(slotIndex, itemStack1); +@@ -242,7 +_,7 @@ + this.lastSlots.set(i, newItem); for (ContainerListener containerListener : this.containerListeners) { -- containerListener.slotChanged(this, slotIndex, itemStack1); -+ containerListener.slotChanged(this, slotIndex, itemStack, itemStack1); // Paper - Add PlayerInventorySlotChangeEvent +- containerListener.slotChanged(this, i, newItem); ++ containerListener.slotChanged(this, i, localExpected, newItem); // Paper - Add PlayerInventorySlotChangeEvent } } } -@@ -349,6 +_,7 @@ +@@ -350,6 +_,7 @@ this.resetQuickCraft(); } } else if (this.quickcraftStatus == 1) { + if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks Slot slot = this.slots.get(slotIndex); - ItemStack carried = this.getCarried(); - if (canItemQuickReplace(slot, carried, true) -@@ -373,6 +_,7 @@ + ItemStack carriedItemStack = this.getCarried(); + if (canItemQuickReplace(slot, carriedItemStack, true) +@@ -374,6 +_,7 @@ } - int count = this.getCarried().getCount(); + int remaining = this.getCarried().getCount(); + it.unimi.dsi.fastutil.ints.Int2ObjectMap draggedSlots = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack) - for (Slot slot1 : this.quickcraftSlots) { - ItemStack carried1 = this.getCarried(); -@@ -385,12 +_,42 @@ - int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack)); - int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min); - count -= min1 - i2; -- slot1.setByPlayer(itemStack.copyWithCount(min1)); + for (Slot slot : this.quickcraftSlots) { + ItemStack carriedItemStack = this.getCarried(); +@@ -386,12 +_,42 @@ + int maxSize = Math.min(source.getMaxStackSize(), slot.getMaxStackSize(source)); + int newCount = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots.size(), this.quickcraftType, source) + carry, maxSize); + remaining -= newCount - carry; +- slot.setByPlayer(source.copyWithCount(newCount)); - } - } - -- itemStack.setCount(count); -- this.setCarried(itemStack); -+ // slot1.setByPlayer(itemStack.copyWithCount(min1)); -+ draggedSlots.put(slot1.index, itemStack.copyWithCount(min1)); // CraftBukkit - Put in map instead of setting +- source.setCount(remaining); +- this.setCarried(source); ++ // slot.setByPlayer(source.copyWithCount(newCount)); ++ draggedSlots.put(slot.index, source.copyWithCount(newCount)); // CraftBukkit - Put in map instead of setting + } + } + + // CraftBukkit start - InventoryDragEvent + org.bukkit.inventory.InventoryView view = this.getBukkitView(); -+ org.bukkit.inventory.ItemStack newCarried = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); -+ newCarried.setAmount(count); ++ org.bukkit.inventory.ItemStack newCarried = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(source); ++ newCarried.setAmount(remaining); + java.util.Map eventMap = new java.util.HashMap<>(); + for (it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry entry : draggedSlots.int2ObjectEntrySet()) { + eventMap.put(entry.getIntKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(entry.getValue())); @@ -156,8 +156,8 @@ } this.resetQuickCraft(); -@@ -404,8 +_,11 @@ - if (slotIndex == SLOT_CLICKED_OUTSIDE) { +@@ -405,8 +_,11 @@ + if (slotIndex == -999) { if (!this.getCarried().isEmpty()) { if (clickAction == ClickAction.PRIMARY) { - player.drop(this.getCarried(), true); @@ -169,13 +169,13 @@ } else { player.drop(this.getCarried().split(1), true); } -@@ -467,8 +_,18 @@ +@@ -468,8 +_,18 @@ } - slot.setChanged(); + slotx.setChanged(); + // CraftBukkit start - Make sure the client has the right slot contents -+ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != Container.MAX_STACK) { -+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem())); ++ if (player instanceof ServerPlayer serverPlayer && slotx.getMaxStackSize() != Container.MAX_STACK) { ++ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slotx.index, slotx.getItem())); + // Updating a crafting inventory makes the client reset the result slot, have to send it again + if (this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.WORKBENCH || this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.CRAFTING) { + serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 0, this.getSlot(0).getItem())); @@ -183,25 +183,25 @@ + } + // CraftBukkit end } - } else if (clickType == ClickType.SWAP && (button >= 0 && button < 9 || button == 40)) { + } else if (containerInput == ContainerInput.SWAP && (buttonNum >= 0 && buttonNum < 9 || buttonNum == 40)) { + if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks - ItemStack item = inventory.getItem(button); - Slot slot = this.slots.get(slotIndex); - ItemStack carried = slot.getItem(); -@@ -528,7 +_,11 @@ + ItemStack source = inventory.getItem(buttonNum); + Slot target = this.slots.get(slotIndex); + ItemStack targetItemStack = target.getItem(); +@@ -529,7 +_,11 @@ } - carried = slot2.safeTake(i1, Integer.MAX_VALUE, player); -- player.drop(carried, true); + itemStack = slotx.safeTake(amount, Integer.MAX_VALUE, player); +- player.drop(itemStack, true); + // CraftBukkit start - SPIGOT-8010: break loop -+ if (player.drop(carried, true) == null) { ++ if (player.drop(itemStack, true) == null) { + break; + } + // CraftBukkit end - SPIGOT-8010: break loop - player.handleCreativeModeItemDrop(carried); + player.handleCreativeModeItemDrop(itemStack); } } -@@ -588,8 +_,9 @@ +@@ -594,8 +_,9 @@ if (player instanceof ServerPlayer) { ItemStack carried = this.getCarried(); if (!carried.isEmpty()) { @@ -212,72 +212,72 @@ } } } -@@ -635,6 +_,14 @@ +@@ -641,6 +_,14 @@ public abstract boolean stillValid(Player player); - protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection) { + protected boolean moveItemStackTo(final ItemStack itemStack, final int startSlot, final int endSlot, final boolean backwards) { + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent -+ return this.moveItemStackTo(stack, startIndex, endIndex, reverseDirection, false); ++ return this.moveItemStackTo(itemStack, startSlot, endSlot, backwards, false); + } -+ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection, boolean isCheck) { ++ protected boolean moveItemStackTo(ItemStack itemStack, final int startSlot, final int endSlot, final boolean backwards, final boolean isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - non-final itemStack + if (isCheck) { -+ stack = stack.copy(); ++ itemStack = itemStack.copy(); + } + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - boolean flag = false; - int i = startIndex; - if (reverseDirection) { -@@ -645,18 +_,27 @@ - while (!stack.isEmpty() && (reverseDirection ? i >= startIndex : i < endIndex)) { - Slot slot = this.slots.get(i); - ItemStack item = slot.getItem(); + boolean anythingChanged = false; + int destSlot = startSlot; + if (backwards) { +@@ -651,18 +_,27 @@ + while (!itemStack.isEmpty() && (backwards ? destSlot >= startSlot : destSlot < endSlot)) { + Slot slot = this.slots.get(destSlot); + ItemStack target = slot.getItem(); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check + if (isCheck) { -+ item = item.copy(); ++ target = target.copy(); + } + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (!item.isEmpty() && ItemStack.isSameItemSameComponents(stack, item)) { - int i1 = item.getCount() + stack.getCount(); - int maxStackSize = slot.getMaxStackSize(item); - if (i1 <= maxStackSize) { - stack.setCount(0); - item.setCount(i1); + if (!target.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, target)) { + int totalStack = target.getCount() + itemStack.getCount(); + int maxStackSize = slot.getMaxStackSize(target); + if (totalStack <= maxStackSize) { + itemStack.setCount(0); + target.setCount(totalStack); + if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent slot.setChanged(); + } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag = true; - } else if (item.getCount() < maxStackSize) { - stack.shrink(maxStackSize - item.getCount()); - item.setCount(maxStackSize); -+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + anythingChanged = true; + } else if (target.getCount() < maxStackSize) { + itemStack.shrink(maxStackSize - target.getCount()); + target.setCount(maxStackSize); ++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent slot.setChanged(); + } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag = true; + anythingChanged = true; } } -@@ -679,10 +_,21 @@ - while (reverseDirection ? i >= startIndex : i < endIndex) { - Slot slotx = this.slots.get(i); - ItemStack itemx = slotx.getItem(); +@@ -685,10 +_,21 @@ + while (backwards ? destSlot >= startSlot : destSlot < endSlot) { + Slot slotx = this.slots.get(destSlot); + ItemStack targetx = slotx.getItem(); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent + if (isCheck) { -+ itemx = itemx.copy(); ++ targetx = targetx.copy(); + } + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (itemx.isEmpty() && slotx.mayPlace(stack)) { - int i1 = slotx.getMaxStackSize(stack); + if (targetx.isEmpty() && slotx.mayPlace(itemStack)) { + int maxStackSize = slotx.getMaxStackSize(itemStack); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent + if (isCheck) { -+ stack.shrink(Math.min(stack.getCount(), i1)); ++ itemStack.shrink(Math.min(itemStack.getCount(), maxStackSize)); + } else { + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - slotx.setByPlayer(stack.split(Math.min(stack.getCount(), i1))); + slotx.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), maxStackSize))); slotx.setChanged(); + } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent - flag = true; + anythingChanged = true; break; } -@@ -766,6 +_,11 @@ +@@ -772,6 +_,11 @@ } public ItemStack getCarried() { @@ -289,7 +289,7 @@ return this.carried; } -@@ -818,4 +_,15 @@ +@@ -825,4 +_,15 @@ this.stateId = this.stateId + 1 & 32767; return this.stateId; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch index 7fc235df80e8..207d19c7a9ee 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/AbstractCraftingMenu.java +++ b/net/minecraft/world/inventory/AbstractCraftingMenu.java -@@ -12,14 +_,17 @@ +@@ -13,14 +_,17 @@ public abstract class AbstractCraftingMenu extends RecipeBookMenu { private final int width; private final int height; @@ -8,8 +8,8 @@ + public final TransientCraftingContainer craftSlots; // CraftBukkit public final ResultContainer resultSlots = new ResultContainer(); -- public AbstractCraftingMenu(MenuType menuType, int containerId, int width, int height) { -+ public AbstractCraftingMenu(MenuType menuType, int containerId, int width, int height, Inventory playerInventory) { // CraftBukkit +- public AbstractCraftingMenu(final MenuType menuType, final int containerId, final int width, final int height) { ++ public AbstractCraftingMenu(final MenuType menuType, final int containerId, final int width, final int height, Inventory playerInventory) { // CraftBukkit super(menuType, containerId); this.width = width; this.height = height; @@ -20,4 +20,4 @@ + // CraftBukkit end } - protected Slot addResultSlot(Player player, int x, int y) { + protected Slot addResultSlot(final Player player, final int x, final int y) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch index cfc170467c77..67a7de55c2ab 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/inventory/AbstractFurnaceMenu.java +++ b/net/minecraft/world/inventory/AbstractFurnaceMenu.java -@@ -34,6 +_,21 @@ +@@ -35,6 +_,21 @@ private final RecipeType recipeType; private final RecipePropertySet acceptedInputs; private final RecipeBookType recipeBookType; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftFurnaceView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftFurnaceView view = null; + private final Inventory inventory; + + @Override @@ -21,8 +21,8 @@ + // CraftBukkit end protected AbstractFurnaceMenu( - MenuType menuType, -@@ -68,6 +_,7 @@ + final MenuType menuType, +@@ -69,6 +_,7 @@ this.addSlot(new Slot(container, 0, 56, 17)); this.addSlot(new FurnaceFuelSlot(this, container, 1, 56, 53)); this.addSlot(new FurnaceResultSlot(inventory.player, container, 2, 116, 35)); @@ -30,10 +30,10 @@ this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlots(data); } -@@ -85,6 +_,7 @@ +@@ -86,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.container.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractMountInventoryMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractMountInventoryMenu.java.patch index 55a058461158..4110ad50b994 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractMountInventoryMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractMountInventoryMenu.java.patch @@ -13,7 +13,7 @@ protected static final int INVENTORY_ROWS = 3; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view; + private final Inventory inventory; + + @Override @@ -26,9 +26,9 @@ + } + // CraftBukkit end + - protected AbstractMountInventoryMenu(int containerId, Inventory playerInventory, Container mountContainer, LivingEntity mount) { + protected AbstractMountInventoryMenu(final int containerId, final Inventory playerInventory, final Container mountInventory, final LivingEntity mount) { super(null, containerId); + this.inventory = playerInventory; // CraftBukkit - this.mountContainer = mountContainer; + this.mountContainer = mountInventory; this.mount = mount; - mountContainer.startOpen(playerInventory.player); + mountInventory.startOpen(playerInventory.player); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch index 73337324a4bb..ea61437e0837 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch @@ -11,14 +11,14 @@ + // CraftBukkit end + public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions - public AnvilMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); + public AnvilMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); @@ -70,7 +_,7 @@ @Override - protected boolean mayPickup(Player player, boolean hasStack) { + protected boolean mayPickup(final Player player, final boolean hasItem) { - return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > 0; -+ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && hasStack; // CraftBukkit - allow cost 0 like a free item ++ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && hasItem; // CraftBukkit - allow cost 0 like a free item } @Override @@ -32,26 +32,26 @@ && !StringUtil.isBlank(this.itemName) && !this.inputSlots.getItem(0).getHoverName().getString().equals(this.itemName)) { @@ -103,6 +_,16 @@ - BlockState blockState = level.getBlockState(blockPos); - if (!player.hasInfiniteMaterials() && blockState.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) { - BlockState blockState1 = AnvilBlock.damage(blockState); + BlockState state = level.getBlockState(pos); + if (!player.hasInfiniteMaterials() && state.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) { + BlockState newBlockState = AnvilBlock.damage(state); + // Paper start - AnvilDamageEvent -+ com.destroystokyo.paper.event.block.AnvilDamagedEvent event = new com.destroystokyo.paper.event.block.AnvilDamagedEvent(getBukkitView(), blockState1 != null ? org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(blockState1) : null); ++ com.destroystokyo.paper.event.block.AnvilDamagedEvent event = new com.destroystokyo.paper.event.block.AnvilDamagedEvent(getBukkitView(), newBlockState != null ? newBlockState.asBlockData() : null); + if (!event.callEvent()) { + return; + } else if (event.getDamageState() == com.destroystokyo.paper.event.block.AnvilDamagedEvent.DamageState.BROKEN) { -+ blockState1 = null; ++ newBlockState = null; + } else { -+ blockState1 = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, blockState.getValue(AnvilBlock.FACING)); ++ newBlockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, state.getValue(AnvilBlock.FACING)); + } + // Paper end - AnvilDamageEvent - if (blockState1 == null) { - level.removeBlock(blockPos, false); - level.levelEvent(LevelEvent.SOUND_ANVIL_BROKEN, blockPos, 0); + if (newBlockState == null) { + level.removeBlock(pos, false); + level.levelEvent(LevelEvent.SOUND_ANVIL_BROKEN, pos, 0); @@ -135,8 +_,8 @@ - if (itemStack.isDamageableItem() && item.isValidRepairItem(item1)) { - int min = Math.min(itemStack.getDamageValue(), itemStack.getMaxDamage() / 4); - if (min <= 0) { + if (result.isDamageableItem() && input.isValidRepairItem(addition)) { + int repairAmount = Math.min(result.getDamageValue(), result.getMaxDamage() / 4); + if (repairAmount <= 0) { - this.resultSlots.setItem(0, ItemStack.EMPTY); - this.cost.set(0); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit @@ -60,9 +60,9 @@ } @@ -151,8 +_,8 @@ - this.repairItemCountCost = i2; + this.repairItemCountCost = count; } else { - if (!hasStoredEnchantments && (!itemStack.is(item1.getItem()) || !itemStack.isDamageableItem())) { + if (!usingBook && (!result.is(addition.getItem()) || !result.isDamageableItem())) { - this.resultSlots.setItem(0, ItemStack.EMPTY); - this.cost.set(0); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit @@ -71,18 +71,18 @@ } @@ -198,7 +_,7 @@ - flag1 = true; + isAnyEnchantmentNotCompatible = true; } else { - flag = true; -- if (intValue > enchantment.getMaxLevel()) { -+ if (intValue > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions - intValue = enchantment.getMaxLevel(); + isAnyEnchantmentCompatible = true; +- if (level > enchantment.getMaxLevel()) { ++ if (level > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions + level = enchantment.getMaxLevel(); } @@ -216,8 +_,8 @@ } - if (flag1 && !flag) { + if (isAnyEnchantmentNotCompatible && !isAnyEnchantmentCompatible) { - this.resultSlots.setItem(0, ItemStack.EMPTY); - this.cost.set(0); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit @@ -93,7 +93,7 @@ @@ -242,14 +_,16 @@ } - if (i1 == i && i1 > 0) { + if (namingCost == price && namingCost > 0) { - if (this.cost.get() >= 40) { - this.cost.set(39); + // CraftBukkit start @@ -107,15 +107,15 @@ - if (this.cost.get() >= 40 && !this.player.hasInfiniteMaterials()) { + if (this.cost.get() >= this.maximumRepairCost && !this.player.hasInfiniteMaterials()) { // CraftBukkit - itemStack = ItemStack.EMPTY; + result = ItemStack.EMPTY; } @@ -267,12 +_,13 @@ - EnchantmentHelper.setEnchantments(itemStack, mutable.toImmutable()); + EnchantmentHelper.setEnchantments(result, enchantments.toImmutable()); } -- this.resultSlots.setItem(0, itemStack); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemStack); // CraftBukkit +- this.resultSlots.setItem(0, result); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), result); // CraftBukkit this.broadcastChanges(); } else { - this.resultSlots.setItem(0, ItemStack.EMPTY); @@ -126,7 +126,7 @@ + this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686, SPIGOT-7931: Always send completed inventory to stay in sync with client } - public static int calculateIncreasedRepairCost(int oldRepairCost) { + public static int calculateIncreasedRepairCost(final int baseCost) { @@ -293,6 +_,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch index 65870483569e..06b1bf622dd2 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch @@ -1,13 +1,17 @@ --- a/net/minecraft/world/inventory/BeaconMenu.java +++ b/net/minecraft/world/inventory/BeaconMenu.java -@@ -22,20 +_,14 @@ +@@ -23,24 +_,14 @@ private static final int USE_ROW_SLOT_START = 28; private static final int USE_ROW_SLOT_END = 37; private static final int NO_EFFECT = 0; - private final Container beacon = new SimpleContainer(1) { +- { +- Objects.requireNonNull(BeaconMenu.this); +- } +- - @Override -- public boolean canPlaceItem(int slot, ItemStack stack) { -- return stack.is(ItemTags.BEACON_PAYMENT_ITEMS); +- public boolean canPlaceItem(final int slot, final ItemStack itemStack) { +- return itemStack.is(ItemTags.BEACON_PAYMENT_ITEMS); - } - - @Override @@ -15,9 +19,8 @@ - return 1; - } - }; -- private final BeaconMenu.PaymentSlot paymentSlot; + private final Container beacon; // Paper - Add missing InventoryHolders Move down -+ private final PaymentSlot paymentSlot; + private final BeaconMenu.PaymentSlot paymentSlot; private final ContainerLevelAccess access; private final ContainerData beaconData; + // CraftBukkit start @@ -25,18 +28,18 @@ + private final net.minecraft.world.entity.player.Inventory inventory; + // CraftBukkit end - public BeaconMenu(int containerId, Container container) { - this(containerId, container, new SimpleContainerData(3), ContainerLevelAccess.NULL); -@@ -43,6 +_,25 @@ + public BeaconMenu(final int containerId, final Container inventory) { + this(containerId, inventory, new SimpleContainerData(3), ContainerLevelAccess.NULL); +@@ -48,6 +_,25 @@ - public BeaconMenu(int containerId, Container container, ContainerData beaconData, ContainerLevelAccess access) { + public BeaconMenu(final int containerId, final Container inventory, final ContainerData beaconData, final ContainerLevelAccess access) { super(MenuType.BEACON, containerId); -+ this.inventory = (net.minecraft.world.entity.player.Inventory) container; // CraftBukkit - TODO: check this ++ this.inventory = (net.minecraft.world.entity.player.Inventory) inventory; // CraftBukkit - TODO: check this + // Paper - Add missing InventoryHolders + this.beacon = new SimpleContainer(this.createBlockHolder(access), 1) { + @Override -+ public boolean canPlaceItem(int slot, ItemStack stack) { -+ return stack.is(ItemTags.BEACON_PAYMENT_ITEMS); ++ public boolean canPlaceItem(final int slot, final ItemStack itemStack) { ++ return itemStack.is(ItemTags.BEACON_PAYMENT_ITEMS); + } + + @Override @@ -53,15 +56,15 @@ checkContainerDataCount(beaconData, 3); this.beaconData = beaconData; this.access = access; -@@ -65,6 +_,7 @@ +@@ -70,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.BEACON); } -@@ -138,13 +_,30 @@ +@@ -143,13 +_,30 @@ public @Nullable Holder getSecondaryEffect() { return decodeEffect(this.beaconData.get(2)); } @@ -71,21 +74,22 @@ + } + // Paper end - Add PlayerChangeBeaconEffectEvent - public void updateEffects(Optional> primaryEffect, Optional> secondaryEffect) { +- public void updateEffects(final Optional> primary, final Optional> secondary) { ++ public void updateEffects(final Optional> primary, Optional> secondary) { // Paper - fix MC-174630 - make non-final + // Paper start - fix MC-174630 - validate secondary power -+ if (secondaryEffect.isPresent() && secondaryEffect.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primaryEffect.isPresent() && secondaryEffect.get() != primaryEffect.get())) { -+ secondaryEffect = Optional.empty(); ++ if (secondary.isPresent() && secondary.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primary.isPresent() && secondary.get() != primary.get())) { ++ secondary = Optional.empty(); + } + // Paper end if (this.paymentSlot.hasItem()) { -- this.beaconData.set(1, encodeEffect(primaryEffect.orElse(null))); -- this.beaconData.set(2, encodeEffect(secondaryEffect.orElse(null))); +- this.beaconData.set(1, encodeEffect(primary.orElse(null))); +- this.beaconData.set(2, encodeEffect(secondary.orElse(null))); + // Paper start - Add PlayerChangeBeaconEffectEvent -+ io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.inventory.player.getBukkitEntity(), convert(primaryEffect), convert(secondaryEffect), this.access.getLocation().getBlock()); ++ io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.inventory.player.getBukkitEntity(), convert(primary), convert(secondary), this.access.getLocation().getBlock()); + if (event.callEvent()) { + // Paper end - Add PlayerChangeBeaconEffectEvent -+ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error -+ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error ++ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary()))); // CraftBukkit ++ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary()))); // CraftBukkit + if (event.willConsumeItem()) { // Paper this.paymentSlot.remove(1); + } // Paper @@ -94,7 +98,7 @@ } } -@@ -167,4 +_,17 @@ +@@ -172,4 +_,17 @@ return 1; } } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch index fb6d90fa6a68..16eb771d6181 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/BrewingStandMenu.java.patch @@ -5,34 +5,34 @@ public final ContainerData brewingStandData; private final Slot ingredientSlot; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftBrewingStandView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftBrewingStandView view = null; + private final Inventory inventory; + // CraftBukkit end - public BrewingStandMenu(int containerId, Inventory playerInventory) { -- this(containerId, playerInventory, new SimpleContainer(5), new SimpleContainerData(2)); -+ this(containerId, playerInventory, new SimpleContainer(5), new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add totalBrewTime + public BrewingStandMenu(final int containerId, final Inventory inventory) { +- this(containerId, inventory, new SimpleContainer(5), new SimpleContainerData(2)); ++ this(containerId, inventory, new SimpleContainer(5), new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add totalBrewTime } - public BrewingStandMenu(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData) { + public BrewingStandMenu(final int containerId, final Inventory inventory, final Container brewingStand, final ContainerData brewingStandData) { super(MenuType.BREWING_STAND, containerId); -+ this.inventory = playerInventory; // CraftBukkit - checkContainerSize(brewingStandContainer, 5); ++ this.inventory = inventory; // CraftBukkit + checkContainerSize(brewingStand, 5); - checkContainerDataCount(brewingStandData, 2); + checkContainerDataCount(brewingStandData, 3); // Paper - Add recipeBrewTime - this.brewingStand = brewingStandContainer; + this.brewingStand = brewingStand; this.brewingStandData = brewingStandData; - PotionBrewing potionBrewing = playerInventory.player.level().potionBrewing(); -- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 0, 56, 51)); -- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 1, 79, 58)); -- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 2, 102, 51)); + PotionBrewing potionBrewing = inventory.player.level().potionBrewing(); +- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 0, 56, 51)); +- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 1, 79, 58)); +- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 2, 102, 51)); + // Paper start - custom potion mixes -+ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 0, 56, 51, potionBrewing)); -+ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 1, 79, 58, potionBrewing)); -+ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 2, 102, 51, potionBrewing)); ++ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 0, 56, 51, potionBrewing)); ++ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 1, 79, 58, potionBrewing)); ++ this.addSlot(new BrewingStandMenu.PotionSlot(brewingStand, 2, 102, 51, potionBrewing)); + // Paper end - custom potion mixes - this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionBrewing, brewingStandContainer, 3, 79, 17)); - this.addSlot(new BrewingStandMenu.FuelSlot(brewingStandContainer, 4, 17, 17)); + this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionBrewing, brewingStand, 3, 79, 17)); + this.addSlot(new BrewingStandMenu.FuelSlot(brewingStand, 4, 17, 17)); - this.addDataSlots(brewingStandData); + // Paper start - Add recipeBrewTime + this.addDataSlots(new SimpleContainerData(2) { @@ -48,50 +48,50 @@ + } + }); + // Paper end - Add recipeBrewTime - this.addStandardInventorySlots(playerInventory, 8, 84); + this.addStandardInventorySlots(inventory, 8, 84); } @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.brewingStand.stillValid(player); } @@ -75,7 +_,7 @@ - if (!this.moveItemStackTo(item, 3, 4, false)) { + if (!this.moveItemStackTo(stack, 3, 4, false)) { return ItemStack.EMPTY; } -- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemStack)) { -+ } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemStack, this.inventory.player.level().potionBrewing())) { // Paper - custom potion mixes - if (!this.moveItemStackTo(item, 0, 3, false)) { +- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(clicked)) { ++ } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(clicked, this.inventory.player.level().potionBrewing())) { // Paper - custom potion mixes + if (!this.moveItemStackTo(stack, 0, 3, false)) { return ItemStack.EMPTY; } @@ -157,13 +_,15 @@ } - static class PotionSlot extends Slot { -- public PotionSlot(Container container, int slot, int x, int y) { + private static class PotionSlot extends Slot { +- public PotionSlot(final Container container, final int slot, final int x, final int y) { + private final PotionBrewing potionBrewing; // Paper - custom potion mixes -+ public PotionSlot(Container container, int slot, int x, int y, PotionBrewing potionBrewing) { // Paper - custom potion mixes ++ public PotionSlot(final Container container, final int slot, final int x, final int y, final PotionBrewing potionBrewing) { // Paper - custom potion mixes super(container, slot, x, y); + this.potionBrewing = potionBrewing; // Paper - custom potion mixes } @Override - public boolean mayPlace(ItemStack stack) { -- return mayPlaceItem(stack); -+ return mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes + public boolean mayPlace(final ItemStack itemStack) { +- return mayPlaceItem(itemStack); ++ return mayPlaceItem(itemStack, this.potionBrewing); // Paper - custom potion mixes } @Override @@ -181,8 +_,8 @@ - super.onTake(player, stack); + super.onTake(player, carried); } -- public static boolean mayPlaceItem(ItemStack stack) { -- return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE); -+ public static boolean mayPlaceItem(ItemStack stack, PotionBrewing potionBrewing) { // Paper - custom potion mixes -+ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack); // Paper - Custom Potion Mixes +- public static boolean mayPlaceItem(final ItemStack itemStack) { +- return itemStack.is(Items.POTION) || itemStack.is(Items.SPLASH_POTION) || itemStack.is(Items.LINGERING_POTION) || itemStack.is(Items.GLASS_BOTTLE); ++ public static boolean mayPlaceItem(final ItemStack itemStack, final PotionBrewing potionBrewing) { // Paper - custom potion mixes) { ++ return itemStack.is(Items.POTION) || itemStack.is(Items.SPLASH_POTION) || itemStack.is(Items.LINGERING_POTION) || itemStack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(itemStack); // Paper - Custom Potion Mixes } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch index d927bf3e9bd3..6a8a2dbc42a4 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/inventory/CartographyTableMenu.java +++ b/net/minecraft/world/inventory/CartographyTableMenu.java -@@ -15,6 +_,21 @@ +@@ -16,6 +_,21 @@ import net.minecraft.world.level.saveddata.maps.MapItemSavedData; public class CartographyTableMenu extends AbstractContainerMenu { + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; + private final org.bukkit.entity.Player player; + + @Override @@ -22,11 +22,15 @@ public static final int MAP_SLOT = 0; public static final int ADDITIONAL_SLOT = 1; public static final int RESULT_SLOT = 2; -@@ -24,20 +_,8 @@ +@@ -25,28 +_,8 @@ private static final int USE_ROW_SLOT_END = 39; private final ContainerLevelAccess access; - long lastSoundTime; + private long lastSoundTime; - public final Container container = new SimpleContainer(2) { +- { +- Objects.requireNonNull(CartographyTableMenu.this); +- } +- - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); @@ -34,6 +38,10 @@ - } - }; - private final ResultContainer resultContainer = new ResultContainer() { +- { +- Objects.requireNonNull(CartographyTableMenu.this); +- } +- - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); @@ -43,11 +51,11 @@ + public final Container container; // Paper - Add missing InventoryHolders - move down + private final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down - public CartographyTableMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); -@@ -45,6 +_,34 @@ + public CartographyTableMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); +@@ -54,6 +_,34 @@ - public CartographyTableMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) { + public CartographyTableMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.CARTOGRAPHY_TABLE, containerId); + // Paper start - Add missing InventoryHolders - move down + this.container = new SimpleContainer(this.createBlockHolder(access), 2) { @@ -79,25 +87,25 @@ + // Paper end - Add missing InventoryHolders - move down this.access = access; this.addSlot(new Slot(this.container, 0, 15, 15) { - @Override -@@ -80,10 +_,12 @@ + { +@@ -101,10 +_,12 @@ } }); - this.addStandardInventorySlots(playerInventory, 8, 84); -+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit + this.addStandardInventorySlots(inventory, 8, 84); ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.CARTOGRAPHY_TABLE); } -@@ -99,6 +_,7 @@ +@@ -120,6 +_,7 @@ } else { this.resultContainer.removeItemNoUpdate(2); } + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } - private void setupResultSlot(ItemStack map, ItemStack firstSlotStack, ItemStack resultOutput) { + private void setupResultSlot(final ItemStack mapStack, final ItemStack additionalStack, final ItemStack resultStack) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ChestMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ChestMenu.java.patch index b65327296886..43f25286dbed 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ChestMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ChestMenu.java.patch @@ -5,7 +5,7 @@ private final Container container; private final int containerRows; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; + private final Inventory inventory; + + @Override @@ -33,24 +33,24 @@ + } + // CraftBukkit end - private ChestMenu(MenuType type, int containerId, Inventory playerInventory, int rows) { - this(type, containerId, playerInventory, new SimpleContainer(9 * rows), rows); + private ChestMenu(final MenuType menuType, final int containerId, final Inventory inventory, final int rows) { + this(menuType, containerId, inventory, new SimpleContainer(9 * rows), rows); @@ -51,7 +_,10 @@ checkContainerSize(container, rows * 9); this.container = container; this.containerRows = rows; -- container.startOpen(playerInventory.player); +- container.startOpen(inventory.player); + // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens + // CraftBukkit start - Save player -+ this.inventory = playerInventory; ++ this.inventory = inventory; + // CraftBukkit end - int i = 18; + int chestGridTop = 18; this.addChestGrid(container, 8, 18); - int i1 = 18 + this.containerRows * 18 + 13; + int inventoryTop = 18 + this.containerRows * 18 + 13; @@ -68,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.container.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ContainerLevelAccess.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ContainerLevelAccess.java.patch index b2a7d2747c6f..2bb6536a97ce 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ContainerLevelAccess.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ContainerLevelAccess.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/inventory/ContainerLevelAccess.java +++ b/net/minecraft/world/inventory/ContainerLevelAccess.java @@ -12,6 +_,12 @@ - public Optional evaluate(BiFunction levelPosConsumer) { + public Optional evaluate(final BiFunction action) { return Optional.empty(); } + // Paper start - fix menus with empty level accesses @@ -14,8 +14,8 @@ static ContainerLevelAccess create(final Level level, final BlockPos pos) { @@ -20,6 +_,23 @@ - public Optional evaluate(BiFunction levelPosConsumer) { - return Optional.of(levelPosConsumer.apply(level, pos)); + public Optional evaluate(final BiFunction action) { + return Optional.of(action.apply(level, pos)); } + // CraftBukkit start + @Override @@ -59,7 +59,7 @@ + return false; + } + -+ default @javax.annotation.Nullable org.bukkit.inventory.BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) { ++ default org.bukkit.inventory.@org.jspecify.annotations.Nullable BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) { + if (!this.isBlock()) { + return null; + } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ContainerListener.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ContainerListener.java.patch index 0f457f3e8be2..da8d59a4b26a 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ContainerListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ContainerListener.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/inventory/ContainerListener.java +++ b/net/minecraft/world/inventory/ContainerListener.java @@ -6,4 +_,10 @@ - void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack stack); + void slotChanged(AbstractContainerMenu container, int slotIndex, ItemStack itemStack); - void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value); + void dataChanged(AbstractContainerMenu container, int id, int value); + + // Paper start - Add PlayerInventorySlotChangeEvent + default void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack oldStack, ItemStack stack) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CrafterMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CrafterMenu.java.patch index 02190277dc44..c5de7b0ab871 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CrafterMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CrafterMenu.java.patch @@ -5,7 +5,7 @@ private final Player player; private final CraftingContainer container; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftCrafterView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftCrafterView view = null; + + @Override + public org.bukkit.craftbukkit.inventory.view.CraftCrafterView getBukkitView() { @@ -19,12 +19,12 @@ + } + // CraftBukkit end - public CrafterMenu(int containerId, Inventory playerInventory) { + public CrafterMenu(final int containerId, final Inventory inventory) { super(MenuType.CRAFTER_3x3, containerId); @@ -100,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.container.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch index c2af45981276..d901921896f5 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CraftingMenu.java.patch @@ -6,20 +6,26 @@ private boolean placingRecipe; + private org.bukkit.craftbukkit.inventory.@Nullable CraftInventoryView view = null; // CraftBukkit - public CraftingMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); + public CraftingMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); } - public CraftingMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) { + public CraftingMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { - super(MenuType.CRAFTING, containerId, 3, 3); -+ super(MenuType.CRAFTING, containerId, 3, 3, playerInventory); // CraftBukkit - pass player ++ super(MenuType.CRAFTING, containerId, 3, 3, inventory); // CraftBukkit - pass player this.access = access; - this.player = playerInventory.player; + this.player = inventory.player; this.addResultSlot(this.player, 124, 35); -@@ -55,7 +_,32 @@ - CraftingInput craftInput = craftSlots.asCraftInput(); +@@ -50,12 +_,37 @@ + final Player player, + final CraftingContainer container, + final ResultContainer resultSlots, +- final @Nullable RecipeHolder recipeHint ++ @Nullable RecipeHolder recipeHint // Paper - Perf: Improve mass crafting; check last recipe used first + ) { + CraftingInput input = container.asCraftInput(); ServerPlayer serverPlayer = (ServerPlayer)player; - ItemStack itemStack = ItemStack.EMPTY; + ItemStack result = ItemStack.EMPTY; + // Paper start - Perf: Improve mass crafting; check last recipe used first + /* + When the server crafts all available items in CraftingMenu or InventoryMenu the game @@ -40,27 +46,27 @@ + + See also: ResultSlot class + */ -+ if (recipe == null) { -+ recipe = craftSlots.getCurrentRecipe(); ++ if (recipeHint == null) { ++ recipeHint = container.getCurrentRecipe(); + } + // Paper end - Perf: Improve mass crafting; check last recipe used first - Optional> recipeFor = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftInput, level, recipe); -+ craftSlots.setCurrentRecipe(recipeFor.orElse(null)); // CraftBukkit - if (recipeFor.isPresent()) { - RecipeHolder recipeHolder = recipeFor.get(); + Optional> maybeRecipe = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, input, level, recipeHint); ++ container.setCurrentRecipe(maybeRecipe.orElse(null)); // CraftBukkit + if (maybeRecipe.isPresent()) { + RecipeHolder recipeHolder = maybeRecipe.get(); CraftingRecipe craftingRecipe = recipeHolder.value(); @@ -66,6 +_,7 @@ } } } -+ itemStack = org.bukkit.craftbukkit.event.CraftEventFactory.callPreCraftEvent(craftSlots, resultSlots, itemStack, menu.getBukkitView(), recipeFor.map(RecipeHolder::value).orElse(null) instanceof net.minecraft.world.item.crafting.RepairItemRecipe); // CraftBukkit ++ result = org.bukkit.craftbukkit.event.CraftEventFactory.callPreCraftEvent(container, resultSlots, result, menu.getBukkitView(), maybeRecipe.map(RecipeHolder::value).orElse(null) instanceof net.minecraft.world.item.crafting.RepairItemRecipe); // CraftBukkit - resultSlots.setItem(0, itemStack); - menu.setRemoteSlot(0, itemStack); + resultSlots.setItem(0, result); + menu.setRemoteSlot(0, result); @@ -102,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.CRAFTING_TABLE); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/DispenserMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/DispenserMenu.java.patch index 739a0a9d10b7..7e5de9a28a0a 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/DispenserMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/DispenserMenu.java.patch @@ -5,26 +5,26 @@ private static final int USE_ROW_SLOT_END = 45; public final Container dispenser; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; + private final Inventory inventory; + // CraftBukkit end - public DispenserMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, new SimpleContainer(9)); + public DispenserMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, new SimpleContainer(9)); @@ -20,6 +_,9 @@ - public DispenserMenu(int containerId, Inventory playerInventory, Container container) { + public DispenserMenu(final int containerId, final Inventory inventory, final Container dispenser) { super(MenuType.GENERIC_3x3, containerId); + // CraftBukkit start - Save player -+ this.inventory = playerInventory; ++ this.inventory = inventory; + // CraftBukkit end - checkContainerSize(container, 9); - this.dispenser = container; - container.startOpen(playerInventory.player); + checkContainerSize(dispenser, 9); + this.dispenser = dispenser; + dispenser.startOpen(inventory.player); @@ -38,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.dispenser.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch index 0a8bd3647751..9e4ceb9aedc1 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -1,10 +1,14 @@ --- a/net/minecraft/world/inventory/EnchantmentMenu.java +++ b/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -31,19 +_,17 @@ +@@ -32,23 +_,17 @@ public class EnchantmentMenu extends AbstractContainerMenu { - static final Identifier EMPTY_SLOT_LAPIS_LAZULI = Identifier.withDefaultNamespace("container/slot/lapis_lazuli"); + private static final Identifier EMPTY_SLOT_LAPIS_LAZULI = Identifier.withDefaultNamespace("container/slot/lapis_lazuli"); - private final Container enchantSlots = new SimpleContainer(2) { +- { +- Objects.requireNonNull(EnchantmentMenu.this); +- } +- - @Override - public void setChanged() { - super.setChanged(); @@ -19,15 +23,15 @@ public final int[] enchantClue = new int[]{-1, -1, -1}; public final int[] levelClue = new int[]{-1, -1, -1}; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftEnchantmentView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftEnchantmentView view = null; + private final org.bukkit.entity.Player player; + // CraftBukkit end - public EnchantmentMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); -@@ -51,6 +_,22 @@ + public EnchantmentMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); +@@ -56,6 +_,22 @@ - public EnchantmentMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) { + public EnchantmentMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.ENCHANTMENT, containerId); + // Paper start - Add missing InventoryHolders + this.enchantSlots = new SimpleContainer(this.createBlockHolder(access), 2) { // Paper - Add missing InventoryHolders @@ -47,37 +51,37 @@ + // Paper end - Add missing InventoryHolders this.access = access; this.addSlot(new Slot(this.enchantSlots, 0, 15, 47) { - @Override -@@ -80,13 +_,14 @@ + { +@@ -93,13 +_,14 @@ this.addDataSlot(DataSlot.shared(this.levelClue, 0)); this.addDataSlot(DataSlot.shared(this.levelClue, 1)); this.addDataSlot(DataSlot.shared(this.levelClue, 2)); -+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } @Override - public void slotsChanged(Container inventory) { - if (inventory == this.enchantSlots) { - ItemStack item = inventory.getItem(0); -- if (!item.isEmpty() && item.isEnchantable()) { -+ if (!item.isEmpty()) { // CraftBukkit - relax condition + public void slotsChanged(final Container container) { + if (container == this.enchantSlots) { + ItemStack itemStack = container.getItem(0); +- if (!itemStack.isEmpty() && itemStack.isEnchantable()) { ++ if (!itemStack.isEmpty()) { // CraftBukkit - relax condition this.access.execute((level, pos) -> { - IdMap> holderIdMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); - int i1 = 0; -@@ -119,6 +_,42 @@ + IdMap> holders = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); + int bookcases = 0; +@@ -132,6 +_,42 @@ } } + // CraftBukkit start -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); + org.bukkit.enchantments.EnchantmentOffer[] offers = new org.bukkit.enchantments.EnchantmentOffer[3]; + for (int j = 0; j < 3; ++j) { -+ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[j] >= 0) ? org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(this.enchantClue[j])) : null; ++ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[j] >= 0) ? org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holders.byId(this.enchantClue[j])) : null; + offers[j] = (enchantment != null) ? new org.bukkit.enchantments.EnchantmentOffer(enchantment, this.levelClue[j], this.costs[j]) : null; + } + -+ org.bukkit.event.enchantment.PrepareItemEnchantEvent event = new org.bukkit.event.enchantment.PrepareItemEnchantEvent(this.player, this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, offers, i1); -+ event.setCancelled(!item.isEnchantable()); ++ org.bukkit.event.enchantment.PrepareItemEnchantEvent event = new org.bukkit.event.enchantment.PrepareItemEnchantEvent(this.player, this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, offers, bookcases); ++ event.setCancelled(!itemStack.isEnchantable()); + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { @@ -93,7 +97,7 @@ + org.bukkit.enchantments.EnchantmentOffer offer = event.getOffers()[j]; + if (offer != null) { + this.costs[j] = offer.getCost(); -+ this.enchantClue[j] = holderIdMap.getId(org.bukkit.craftbukkit.enchantments.CraftEnchantment ++ this.enchantClue[j] = holders.getId(org.bukkit.craftbukkit.enchantments.CraftEnchantment + .bukkitToMinecraftHolder(offer.getEnchantment())); + this.levelClue[j] = offer.getEnchantmentLevel(); + } else { @@ -107,28 +111,28 @@ this.broadcastChanges(); }); } else { -@@ -145,19 +_,52 @@ +@@ -158,19 +_,52 @@ return false; } else { this.access.execute((level, pos) -> { -- ItemStack itemStack = item; -+ ItemStack itemStack = item; // Paper - diff on change - List enchantmentList = this.getEnchantmentList(level.registryAccess(), item, id, this.costs[id]); -- if (!enchantmentList.isEmpty()) { +- ItemStack enchantmentItem = itemStack; ++ ItemStack enchantmentItem = itemStack; // Paper - diff on change + List newEnchantment = this.getEnchantmentList(level.registryAccess(), itemStack, buttonId, this.costs[buttonId]); +- if (!newEnchantment.isEmpty()) { + // CraftBukkit start + IdMap> registry = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); -+ if (true || !enchantmentList.isEmpty()) { -+ // player.onEnchantmentPerformed(item, i); // Moved down ++ if (true || !newEnchantment.isEmpty()) { ++ // player.onEnchantmentPerformed(itemStack, enchantmentCost); // Moved down + java.util.Map enchants = new java.util.HashMap<>(); -+ for (EnchantmentInstance instance : enchantmentList) { ++ for (EnchantmentInstance instance : newEnchantment) { + enchants.put(org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(instance.enchantment()), instance.level()); + } -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); -+ Holder holder = registry.byId(this.enchantClue[id]); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(enchantmentItem); ++ Holder holder = registry.byId(this.enchantClue[buttonId]); + if (holder == null) return; + org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holder); -+ int hintedEnchantmentLevel = this.levelClue[id]; -+ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[id], enchants, hintedEnchantment, hintedEnchantmentLevel, id); ++ int hintedEnchantmentLevel = this.levelClue[buttonId]; ++ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[buttonId], enchants, hintedEnchantment, hintedEnchantmentLevel, buttonId); + level.getCraftServer().getPluginManager().callEvent(event); + int itemLevel = event.getExpLevelCost(); + if (event.isCancelled() || (itemLevel > player.experienceLevel && !player.getAbilities().instabuild) || event.getEnchantsToAdd().isEmpty()) { @@ -136,43 +140,43 @@ + } + // CraftBukkit end + // Paper start -+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(craftItemStack, event.getItem()); -+ if (itemStack != item) { -+ this.enchantSlots.setItem(0, itemStack); ++ enchantmentItem = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(craftItemStack, event.getItem()); ++ if (enchantmentItem != itemStack) { ++ this.enchantSlots.setItem(0, enchantmentItem); + } -+ if (itemStack.is(Items.BOOK)) { -+ itemStack = itemStack.transmuteCopy(Items.ENCHANTED_BOOK); -+ this.enchantSlots.setItem(0, itemStack); ++ if (enchantmentItem.is(Items.BOOK)) { ++ enchantmentItem = enchantmentItem.transmuteCopy(Items.ENCHANTED_BOOK); ++ this.enchantSlots.setItem(0, enchantmentItem); + } + // Paper end + + // CraftBukkit start + for (java.util.Map.Entry entry : event.getEnchantsToAdd().entrySet()) { -+ Holder enchant = org.bukkit.craftbukkit.enchantments.CraftEnchantment.bukkitToMinecraftHolder(entry.getKey()); -+ if (enchant == null) { ++ Holder enchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.bukkitToMinecraftHolder(entry.getKey()); ++ if (enchantment == null) { + continue; + } + -+ itemStack.enchant(enchant, entry.getValue()); ++ enchantmentItem.enchant(enchantment, entry.getValue()); + } + // CraftBukkit end - player.onEnchantmentPerformed(item, i); -- if (item.is(Items.BOOK)) { -- itemStack = item.transmuteCopy(Items.ENCHANTED_BOOK); -- this.enchantSlots.setItem(0, itemStack); + player.onEnchantmentPerformed(itemStack, enchantmentCost); +- if (itemStack.is(Items.BOOK)) { +- enchantmentItem = itemStack.transmuteCopy(Items.ENCHANTED_BOOK); +- this.enchantSlots.setItem(0, enchantmentItem); - } - -- for (EnchantmentInstance enchantmentInstance : enchantmentList) { -- itemStack.enchant(enchantmentInstance.enchantment(), enchantmentInstance.level()); +- for (EnchantmentInstance enchantment : newEnchantment) { +- enchantmentItem.enchant(enchantment.enchantment(), enchantment.level()); - } - + + // CraftBukkit - TODO: let plugins change this - item1.consume(i, player); - if (item1.isEmpty()) { + currency.consume(enchantmentCost, player); + if (currency.isEmpty()) { this.enchantSlots.setItem(1, ItemStack.EMPTY); -@@ -202,6 +_,12 @@ - return item.isEmpty() ? 0 : item.getCount(); +@@ -215,6 +_,12 @@ + return goldStack.isEmpty() ? 0 : goldStack.getCount(); } + // Paper start - add enchantment seed update API @@ -184,17 +188,17 @@ public int getEnchantmentSeed() { return this.enchantmentSeed.get(); } -@@ -214,6 +_,7 @@ +@@ -227,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.ENCHANTING_TABLE); } -@@ -261,4 +_,17 @@ +@@ -274,4 +_,17 @@ - return itemStack; + return clicked; } + + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/FurnaceResultSlot.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/FurnaceResultSlot.java.patch index 5f4858a6d130..a94ad0f3c913 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/FurnaceResultSlot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/FurnaceResultSlot.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/inventory/FurnaceResultSlot.java +++ b/net/minecraft/world/inventory/FurnaceResultSlot.java @@ -45,7 +_,7 @@ - protected void checkTakeAchievements(ItemStack stack) { - stack.onCraftedBy(this.player, this.removeCount); + protected void checkTakeAchievements(final ItemStack carried) { + carried.onCraftedBy(this.player, this.removeCount); if (this.player instanceof ServerPlayer serverPlayer && this.container instanceof AbstractFurnaceBlockEntity abstractFurnaceBlockEntity) { - abstractFurnaceBlockEntity.awardUsedRecipesAndPopExperience(serverPlayer); -+ abstractFurnaceBlockEntity.awardUsedRecipesAndPopExperience(serverPlayer, stack, this.removeCount); // CraftBukkit ++ abstractFurnaceBlockEntity.awardUsedRecipesAndPopExperience(serverPlayer, carried, this.removeCount); // CraftBukkit } this.removeCount = 0; diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 06fc1bb17cde..62e740e61299 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/inventory/GrindstoneMenu.java +++ b/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -21,6 +_,21 @@ +@@ -22,6 +_,21 @@ import net.minecraft.world.phys.Vec3; public class GrindstoneMenu extends AbstractContainerMenu { + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; + private final org.bukkit.entity.Player player; + + @Override @@ -22,12 +22,16 @@ public static final int MAX_NAME_LENGTH = 35; public static final int INPUT_SLOT = 0; public static final int ADDITIONAL_SLOT = 1; -@@ -29,14 +_,8 @@ +@@ -30,18 +_,8 @@ private static final int INV_SLOT_END = 30; private static final int USE_ROW_SLOT_START = 30; private static final int USE_ROW_SLOT_END = 39; - private final Container resultSlots = new ResultContainer(); -- final Container repairSlots = new SimpleContainer(2) { +- private final Container repairSlots = new SimpleContainer(2) { +- { +- Objects.requireNonNull(GrindstoneMenu.this); +- } +- - @Override - public void setChanged() { - super.setChanged(); @@ -38,10 +42,10 @@ + final Container repairSlots; // Paper - Add missing InventoryHolders - move down private final ContainerLevelAccess access; - public GrindstoneMenu(int containerId, Inventory playerInventory) { -@@ -45,6 +_,22 @@ + public GrindstoneMenu(final int containerId, final Inventory inventory) { +@@ -50,6 +_,22 @@ - public GrindstoneMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) { + public GrindstoneMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.GRINDSTONE, containerId); + // Paper start - Add missing InventoryHolders + this.resultSlots = new ResultContainer(this.createBlockHolder(access)); // Paper - Add missing InventoryHolders @@ -61,31 +65,31 @@ + // Paper end - Add missing InventoryHolders this.access = access; this.addSlot(new Slot(this.repairSlots, 0, 49, 19) { - @Override -@@ -68,7 +_,11 @@ - public void onTake(Player player, ItemStack stack) { - access.execute((level, blockPos) -> { + { +@@ -85,7 +_,11 @@ + public void onTake(final Player player, final ItemStack carried) { + access.execute((level, pos) -> { if (level instanceof ServerLevel) { -- ExperienceOrb.award((ServerLevel)level, Vec3.atCenterOf(blockPos), this.getExperienceAmount(level)); +- ExperienceOrb.award((ServerLevel)level, Vec3.atCenterOf(pos), this.getExperienceAmount(level)); + // Paper start - Fire BlockExpEvent on grindstone use -+ org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), this.getExperienceAmount(level)); ++ org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), this.getExperienceAmount(level)); + event.callEvent(); -+ ExperienceOrb.awardWithDirection((ServerLevel) level, Vec3.atCenterOf(blockPos), Vec3.ZERO, event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player, null); ++ ExperienceOrb.awardWithDirection((ServerLevel) level, Vec3.atCenterOf(pos), Vec3.ZERO, event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player, null); + // Paper end - Fire BlockExpEvent on grindstone use } - level.levelEvent(LevelEvent.SOUND_GRINDSTONE_USED, blockPos, 0); -@@ -105,6 +_,7 @@ + level.levelEvent(LevelEvent.SOUND_GRINDSTONE_USED, pos, 0); +@@ -122,6 +_,7 @@ } }); - this.addStandardInventorySlots(playerInventory, 8, 84); -+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit + this.addStandardInventorySlots(inventory, 8, 84); ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } @Override -@@ -112,11 +_,13 @@ - super.slotsChanged(inventory); - if (inventory == this.repairSlots) { +@@ -129,11 +_,13 @@ + super.slotsChanged(container); + if (container == this.repairSlots) { this.createResult(); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } @@ -98,10 +102,10 @@ this.broadcastChanges(); } -@@ -202,6 +_,7 @@ +@@ -221,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.GRINDSTONE); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/HopperMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/HopperMenu.java.patch index 17d3a0332a1f..69ef0414a894 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/HopperMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/HopperMenu.java.patch @@ -5,7 +5,7 @@ public static final int CONTAINER_SIZE = 5; private final Container hopper; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; + private final Inventory inventory; + + @Override @@ -20,20 +20,20 @@ + } + // CraftBukkit end - public HopperMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, new SimpleContainer(5)); + public HopperMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, new SimpleContainer(5)); @@ -17,6 +_,7 @@ - public HopperMenu(int containerId, Inventory playerInventory, Container container) { + public HopperMenu(final int containerId, final Inventory inventory, final Container hopper) { super(MenuType.HOPPER, containerId); - this.hopper = container; -+ this.inventory = playerInventory; // CraftBukkit - checkContainerSize(container, 5); - container.startOpen(playerInventory.player); + this.hopper = hopper; ++ this.inventory = inventory; // CraftBukkit + checkContainerSize(hopper, 5); + hopper.startOpen(inventory.player); @@ -29,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.hopper.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch index 5a34b07001ad..34d8de1b61cd 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/inventory/InventoryMenu.java +++ b/net/minecraft/world/inventory/InventoryMenu.java -@@ -44,9 +_,13 @@ +@@ -45,9 +_,13 @@ private static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET}; public final boolean active; private final Player owner; -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view = null; // CraftBukkit ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view = null; // CraftBukkit - public InventoryMenu(Inventory playerInventory, boolean active, final Player owner) { + public InventoryMenu(final Inventory inventory, final boolean active, final Player owner) { - super(null, 0, 2, 2); + // CraftBukkit start -+ super(null, 0, 2, 2, playerInventory); // CraftBukkit ++ super(null, 0, 2, 2, inventory); // CraftBukkit + this.setTitle(net.minecraft.network.chat.Component.translatable("container.crafting")); // SPIGOT-4722: Allocate title for player inventory + // CraftBukkit end this.active = active; this.owner = owner; this.addResultSlot(owner, 154, 28); -@@ -188,4 +_,54 @@ +@@ -193,4 +_,54 @@ protected Player owner() { return this.owner; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch index 942a38db2986..dc86a706abf5 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch @@ -1,10 +1,14 @@ --- a/net/minecraft/world/inventory/ItemCombinerMenu.java +++ b/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -15,12 +_,7 @@ +@@ -16,16 +_,7 @@ protected final ContainerLevelAccess access; protected final Player player; protected final Container inputSlots; - protected final ResultContainer resultSlots = new ResultContainer() { +- { +- Objects.requireNonNull(ItemCombinerMenu.this); +- } +- - @Override - public void setChanged() { - ItemCombinerMenu.this.slotsChanged(this); @@ -13,13 +17,17 @@ + protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init private final int resultSlotIndex; - protected boolean mayPickup(Player player, boolean hasStack) { -@@ -36,6 +_,14 @@ + protected boolean mayPickup(final Player player, final boolean hasItem) { +@@ -45,6 +_,18 @@ ) { super(menuType, containerId); this.access = access; + // Paper start - Add missing InventoryHolders; delay field init + this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) { ++ { ++ Objects.requireNonNull(ItemCombinerMenu.this); ++ } ++ + @Override + public void setChanged() { + ItemCombinerMenu.this.slotsChanged(this); @@ -27,29 +35,48 @@ + }; + // Paper end - Add missing InventoryHolders; delay field init this.player = inventory.player; - this.inputSlots = this.createContainer(slotDefinition.getNumOfInputSlots()); - this.resultSlotIndex = slotDefinition.getResultSlotIndex(); -@@ -79,7 +_,7 @@ + this.inputSlots = this.createContainer(itemInputSlots.getNumOfInputSlots()); + this.resultSlotIndex = itemInputSlots.getResultSlotIndex(); +@@ -54,15 +_,15 @@ + } + + private void createInputSlots(final ItemCombinerMenuSlotDefinition itemInputSlots) { +- for (final ItemCombinerMenuSlotDefinition.SlotDefinition slot : itemInputSlots.getSlots()) { +- this.addSlot(new Slot(this.inputSlots, slot.slotIndex(), slot.x(), slot.y()) { ++ for (final ItemCombinerMenuSlotDefinition.SlotDefinition slotDefinition : itemInputSlots.getSlots()) { // Paper - fix conflicting variable name ++ this.addSlot(new Slot(this.inputSlots, slotDefinition.slotIndex(), slotDefinition.x(), slotDefinition.y()) { // Paper - fix conflicting variable name + { + Objects.requireNonNull(ItemCombinerMenu.this); + } + + @Override + public boolean mayPlace(final ItemStack itemStack) { +- return slot.mayPlace().test(itemStack); ++ return slotDefinition.mayPlace().test(itemStack); // Paper - fix conflicting variable name + } + }); + } +@@ -96,7 +_,7 @@ public abstract void createResult(); - private SimpleContainer createContainer(int size) { + private SimpleContainer createContainer(final int size) { - return new SimpleContainer(size) { + return new SimpleContainer(this.createBlockHolder(this.access), size) { - @Override - public void setChanged() { - super.setChanged(); -@@ -93,6 +_,7 @@ - super.slotsChanged(inventory); - if (inventory == this.inputSlots) { + { + Objects.requireNonNull(ItemCombinerMenu.this); + } +@@ -114,6 +_,7 @@ + super.slotsChanged(container); + if (container == this.inputSlots) { this.createResult(); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper - Add PrepareResultEvent } } -@@ -104,6 +_,7 @@ +@@ -125,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.access .evaluate((level, pos) -> !this.isValidBlock(level.getBlockState(pos)) ? false : player.isWithinBlockInteractionRange(pos, 4.0), true); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch index 2f73276c279a..dc23de136d67 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/inventory/LecternMenu.java +++ b/net/minecraft/world/inventory/LecternMenu.java -@@ -14,12 +_,29 @@ +@@ -15,12 +_,29 @@ public static final int BUTTON_PAGE_JUMP_RANGE_START = 100; private final Container lectern; private final ContainerData lecternData; - -- public LecternMenu(int containerId) { +- public LecternMenu(final int containerId) { - this(containerId, new SimpleContainer(1), new SimpleContainerData(1)); - } - -- public LecternMenu(int containerId, Container lectern, ContainerData lecternData) { +- public LecternMenu(final int containerId, final Container lectern, final ContainerData lecternData) { + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftLecternView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftLecternView view = null; + private final org.bukkit.entity.Player player; + + @Override @@ -27,36 +27,36 @@ + // CraftBukkit end + + // CraftBukkit start - add player inventory -+ public LecternMenu(int containerId, net.minecraft.world.entity.player.Inventory playerinventory) { -+ this(containerId, new SimpleContainer(1), new SimpleContainerData(1), playerinventory); ++ public LecternMenu(final int containerId, final net.minecraft.world.entity.player.Inventory inventory) { ++ this(containerId, new SimpleContainer(1), new SimpleContainerData(1), inventory); + } + -+ public LecternMenu(int containerId, Container lectern, ContainerData lecternData, net.minecraft.world.entity.player.Inventory playerinventory) { ++ public LecternMenu(final int containerId, final Container lectern, final ContainerData lecternData, net.minecraft.world.entity.player.Inventory inventory) { + // CraftBukkit end - add player inventory super(MenuType.LECTERN, containerId); checkContainerSize(lectern, 1); checkContainerDataCount(lecternData, 1); -@@ -33,10 +_,12 @@ +@@ -38,10 +_,12 @@ } }); this.addDataSlots(lecternData); -+ this.player = (org.bukkit.entity.Player) playerinventory.player.getBukkitEntity(); // CraftBukkit ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } @Override - public boolean clickMenuButton(Player player, int id) { + public boolean clickMenuButton(final Player player, final int buttonId) { + io.papermc.paper.event.player.PlayerLecternPageChangeEvent playerLecternPageChangeEvent; org.bukkit.craftbukkit.inventory.CraftInventoryLectern bukkitView; // Paper - Add PlayerLecternPageChangeEvent - if (id >= 100) { - int i = id - 100; - this.setData(0, i); -@@ -45,12 +_,26 @@ - switch (id) { + if (buttonId >= 100) { + int pageToSet = buttonId - 100; + this.setData(0, pageToSet); +@@ -50,12 +_,26 @@ + switch (buttonId) { case 1: { - int i = this.lecternData.get(0); -- this.setData(0, i - 1); + int currentPage = this.lecternData.get(0); +- this.setData(0, currentPage - 1); + // Paper start - Add PlayerLecternPageChangeEvent + bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, i, i - 1); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, currentPage, currentPage - 1); + if (!playerLecternPageChangeEvent.callEvent()) { + return false; + } @@ -65,11 +65,11 @@ return true; } case 2: { - int i = this.lecternData.get(0); -- this.setData(0, i + 1); + int currentPage = this.lecternData.get(0); +- this.setData(0, currentPage + 1); + // Paper start - Add PlayerLecternPageChangeEvent + bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, i, i + 1); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, currentPage, currentPage + 1); + if (!playerLecternPageChangeEvent.callEvent()) { + return false; + } @@ -78,25 +78,24 @@ return true; } case 3: -@@ -58,6 +_,13 @@ +@@ -63,6 +_,12 @@ return false; } + // CraftBukkit start - Event for taking the book + org.bukkit.event.player.PlayerTakeLecternBookEvent event = new org.bukkit.event.player.PlayerTakeLecternBookEvent(this.player, this.getBukkitView().getTopInventory().getHolder()); -+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { ++ if (!event.callEvent()) { + return false; + } + // CraftBukkit end - ItemStack itemStack = this.lectern.removeItemNoUpdate(0); + ItemStack book = this.lectern.removeItemNoUpdate(0); this.lectern.setChanged(); - if (!player.getInventory().add(itemStack)) { -@@ -84,6 +_,8 @@ + if (!player.getInventory().add(book)) { +@@ -89,6 +_,8 @@ @Override - public boolean stillValid(Player player) { -+ if (this.lectern instanceof net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory && !((net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory) this.lectern).getLectern().hasBook()) return false; // CraftBukkit + public boolean stillValid(final Player player) { ++ if (this.lectern instanceof net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory lecternInventory && !lecternInventory.getLectern().hasBook()) return false; // CraftBukkit + if (!this.checkReachable) return true; // CraftBukkit return this.lectern.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch index 66aebda55cd6..4e4bf954797f 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch @@ -1,10 +1,14 @@ --- a/net/minecraft/world/inventory/LoomMenu.java +++ b/net/minecraft/world/inventory/LoomMenu.java -@@ -38,21 +_,23 @@ +@@ -39,29 +_,23 @@ private final Slot patternSlot; private final Slot resultSlot; - long lastSoundTime; + private long lastSoundTime; - private final Container inputContainer = new SimpleContainer(3) { +- { +- Objects.requireNonNull(LoomMenu.this); +- } +- - @Override - public void setChanged() { - super.setChanged(); @@ -13,6 +17,10 @@ - } - }; - private final Container outputContainer = new SimpleContainer(1) { +- { +- Objects.requireNonNull(LoomMenu.this); +- } +- - @Override - public void setChanged() { - super.setChanged(); @@ -22,7 +30,7 @@ + private final Container inputContainer; // Paper - Add missing InventoryHolders - move down + private final Container outputContainer; // Paper - Add missing InventoryHolders - move down + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftLoomView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftLoomView view = null; + private final org.bukkit.entity.Player player; + + @Override @@ -37,10 +45,10 @@ + } + // CraftBukkit end - public LoomMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); -@@ -61,6 +_,28 @@ - public LoomMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) { + public LoomMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); +@@ -70,6 +_,28 @@ + public LoomMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.LOOM, containerId); this.access = access; + // CraftBukkit start @@ -66,28 +74,31 @@ + }; + // CraftBukkit end this.bannerSlot = this.addSlot(new Slot(this.inputContainer, 0, 13, 26) { - @Override - public boolean mayPlace(ItemStack stack) { -@@ -106,18 +_,44 @@ - this.addStandardInventorySlots(playerInventory, 8, 84); + { + Objects.requireNonNull(LoomMenu.this); +@@ -131,6 +_,7 @@ + this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlot(this.selectedBannerPatternIndex); - this.patternGetter = playerInventory.player.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN); -+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit + this.patternGetter = inventory.player.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN); ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } + private static boolean isPatternItem(final ItemStack itemStack) { +@@ -143,14 +_,39 @@ + @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.LOOM); } @Override - public boolean clickMenuButton(Player player, int id) { - if (id >= 0 && id < this.selectablePatterns.size()) { -- this.selectedBannerPatternIndex.set(id); -- this.setupResultSlot(this.selectablePatterns.get(id)); + public boolean clickMenuButton(final Player player, final int buttonId) { + if (buttonId >= 0 && buttonId < this.selectablePatterns.size()) { +- this.selectedBannerPatternIndex.set(buttonId); +- this.setupResultSlot(this.selectablePatterns.get(buttonId)); + // Paper start - Add PlayerLoomPatternSelectEvent -+ int selectablePatternIndex = id; ++ int selectablePatternIndex = buttonId; + io.papermc.paper.event.player.PlayerLoomPatternSelectEvent event = new io.papermc.paper.event.player.PlayerLoomPatternSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView().getTopInventory(), org.bukkit.craftbukkit.block.banner.CraftPatternType.minecraftHolderToBukkit(this.selectablePatterns.get(selectablePatternIndex))); + if (!event.callEvent()) { + player.containerMenu.sendAllDataToRemote(); @@ -115,7 +126,7 @@ return true; } else { return false; -@@ -181,7 +_,8 @@ +@@ -212,7 +_,8 @@ this.resultSlot.set(ItemStack.EMPTY); } @@ -125,19 +136,19 @@ } else { this.resultSlot.set(ItemStack.EMPTY); this.selectablePatterns = List.of(); -@@ -270,7 +_,14 @@ - itemStack.update( - DataComponents.BANNER_PATTERNS, - BannerPatternLayers.EMPTY, -- bannerPatternLayers -> new BannerPatternLayers.Builder().addAll(bannerPatternLayers).add(pattern, dyeColor).build() -+ // CraftBukkit start -+ bannerPatternLayers -> { -+ if (bannerPatternLayers.layers().size() > 20) { -+ bannerPatternLayers = new BannerPatternLayers(List.copyOf(bannerPatternLayers.layers().subList(0, 20))); +@@ -302,7 +_,14 @@ + result.update( + DataComponents.BANNER_PATTERNS, + BannerPatternLayers.EMPTY, +- layers -> new BannerPatternLayers.Builder().addAll(layers).add(pattern, patternColor).build() ++ // CraftBukkit start ++ layers -> { ++ if (layers.layers().size() > 20) { ++ layers = new BannerPatternLayers(List.copyOf(layers.layers().subList(0, 20))); ++ } ++ return new BannerPatternLayers.Builder().addAll(layers).add(pattern, patternColor).build(); + } -+ return new BannerPatternLayers.Builder().addAll(bannerPatternLayers).add(pattern, dyeColor).build(); -+ } -+ // CraftBukkit end - ); ++ // CraftBukkit end + ); + } } - diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/MenuType.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/MenuType.java.patch index a5767492ae1b..b76d59df6740 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/MenuType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/MenuType.java.patch @@ -4,7 +4,7 @@ public static final MenuType FURNACE = register("furnace", FurnaceMenu::new); public static final MenuType GRINDSTONE = register("grindstone", GrindstoneMenu::new); public static final MenuType HOPPER = register("hopper", HopperMenu::new); -- public static final MenuType LECTERN = register("lectern", (containerId, playerInventory) -> new LecternMenu(containerId)); +- public static final MenuType LECTERN = register("lectern", (containerId, inventory) -> new LecternMenu(containerId)); + public static final MenuType LECTERN = register("lectern", LecternMenu::new); // CraftBukkit public static final MenuType LOOM = register("loom", LoomMenu::new); public static final MenuType MERCHANT = register("merchant", MerchantMenu::new); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantContainer.java.patch index 043e9ad15879..94698cdaefeb 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantContainer.java.patch @@ -34,15 +34,15 @@ + this.maxStack = size; + } + -+ public @javax.annotation.Nullable org.bukkit.inventory.InventoryHolder getOwner() { -+ return (this.merchant instanceof net.minecraft.world.entity.npc.villager.AbstractVillager abstractVillager) ? (org.bukkit.craftbukkit.entity.CraftAbstractVillager) abstractVillager.getBukkitEntity() : null; ++ public org.bukkit.inventory.@Nullable InventoryHolder getOwner() { ++ return (this.merchant instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) ? (org.bukkit.craftbukkit.entity.CraftAbstractVillager) villager.getBukkitEntity() : null; + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.Location getLocation() { -+ return (this.merchant instanceof net.minecraft.world.entity.npc.villager.AbstractVillager abstractVillager) ? abstractVillager.getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations ++ public org.bukkit.@Nullable Location getLocation() { ++ return (this.merchant instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) ? villager.getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations + } + // CraftBukkit end - public MerchantContainer(Merchant merchant) { - this.merchant = merchant; + public MerchantContainer(final Merchant villager) { + this.merchant = villager; diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantMenu.java.patch index fec640cad860..2fa9d6af0183 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantMenu.java.patch @@ -5,7 +5,7 @@ private boolean showProgressBar; private boolean canRestock; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftMerchantView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftMerchantView view = null; + private final Inventory inventory; + + @Override @@ -17,70 +17,70 @@ + } + // CraftBukkit end - public MerchantMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, new ClientSideMerchant(playerInventory.player)); + public MerchantMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, new ClientSideMerchant(inventory.player)); @@ -42,6 +_,7 @@ this.addSlot(new Slot(this.tradeContainer, 0, 136, 37)); this.addSlot(new Slot(this.tradeContainer, 1, 162, 37)); - this.addSlot(new MerchantResultSlot(playerInventory.player, trader, this.tradeContainer, 2, 220, 37)); -+ this.inventory = playerInventory; // CraftBukkit - this.addStandardInventorySlots(playerInventory, 108, 84); + this.addSlot(new MerchantResultSlot(inventory.player, merchant, this.tradeContainer, 2, 220, 37)); ++ this.inventory = inventory; // CraftBukkit + this.addStandardInventorySlots(inventory, 108, 84); } @@ -61,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!checkReachable) return true; // Paper - checkReachable return this.trader.stillValid(player); } @@ -105,12 +_,12 @@ - ItemStack item = slot.getItem(); - itemStack = item.copy(); + ItemStack stack = slot.getItem(); + clicked = stack.copy(); if (slotIndex == 2) { -- if (!this.moveItemStackTo(item, 3, 39, true)) { -+ if (!this.moveItemStackTo(item, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent +- if (!this.moveItemStackTo(stack, 3, 39, true)) { ++ if (!this.moveItemStackTo(stack, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent return ItemStack.EMPTY; } -- slot.onQuickCraft(item, itemStack); +- slot.onQuickCraft(stack, clicked); - this.playTradeSound(); -+ // slot.onQuickCraft(item, itemStack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call ++ // slot.onQuickCraft(stack, clicked); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call + // this.playTradeSound(); } else if (slotIndex != 0 && slotIndex != 1) { if (slotIndex >= 3 && slotIndex < 30) { - if (!this.moveItemStackTo(item, 30, 39, false)) { + if (!this.moveItemStackTo(stack, 30, 39, false)) { @@ -123,6 +_,7 @@ return ItemStack.EMPTY; } + if (slotIndex != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2 - if (item.isEmpty()) { + if (stack.isEmpty()) { slot.setByPlayer(ItemStack.EMPTY); } else { @@ -134,13 +_,28 @@ } - slot.onTake(player, item); + slot.onTake(player, stack); + } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2 + if (slotIndex == 2) { // is merchant result slot -+ slot.onTake(player, item); -+ if (item.isEmpty()) { ++ slot.onTake(player, stack); ++ if (stack.isEmpty()) { + slot.set(ItemStack.EMPTY); + return ItemStack.EMPTY; + } + -+ this.moveItemStackTo(item, 3, 39, true, false); // This should always succeed because it's checked above ++ this.moveItemStackTo(stack, 3, 39, true, false); // This should always succeed because it's checked above + -+ slot.onQuickCraft(item, itemStack); ++ slot.onQuickCraft(stack, clicked); + this.playTradeSound(); + slot.set(ItemStack.EMPTY); // item should ALWAYS be empty + } + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent } - return itemStack; + return clicked; } private void playTradeSound() { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantResultSlot.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantResultSlot.java.patch index cc2a6f28f895..aefc85bb40fd 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/MerchantResultSlot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/MerchantResultSlot.java.patch @@ -3,37 +3,37 @@ @@ -47,13 +_,34 @@ @Override - public void onTake(Player player, ItemStack stack) { -- this.checkTakeAchievements(stack); -+ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled - MerchantOffer activeOffer = this.slots.getActiveOffer(); + public void onTake(final Player player, final ItemStack carried) { +- this.checkTakeAchievements(carried); ++ // this.checkTakeAchievements(carried); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled + MerchantOffer offer = this.slots.getActiveOffer(); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent + io.papermc.paper.event.player.PlayerPurchaseEvent event = null; -+ if (activeOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ if (offer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { + if (this.merchant instanceof net.minecraft.world.entity.npc.villager.AbstractVillager abstractVillager) { -+ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), activeOffer.asBukkit(), true, true); ++ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), offer.asBukkit(), true, true); + } else if (this.merchant instanceof org.bukkit.craftbukkit.inventory.CraftMerchantCustom.MinecraftMerchant minecraftMerchant) { -+ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), minecraftMerchant.getCraftMerchant(), activeOffer.asBukkit(), false, true); ++ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), minecraftMerchant.getCraftMerchant(), offer.asBukkit(), false, true); + } + if (event != null) { + if (!event.callEvent()) { -+ stack.setCount(0); ++ carried.setCount(0); + player.containerMenu.sendAllDataToRemote(); + int level = merchant instanceof net.minecraft.world.entity.npc.villager.Villager villager ? villager.getVillagerData().level() : 1; + serverPlayer.sendMerchantOffers(player.containerMenu.containerId, merchant.getOffers(), level, merchant.getVillagerXp(), merchant.showProgressBar(), merchant.canRestock()); + return; + } -+ activeOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft(); ++ offer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft(); + } + } -+ this.checkTakeAchievements(stack); ++ this.checkTakeAchievements(carried); + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (activeOffer != null) { - ItemStack item = this.slots.getItem(0); - ItemStack item1 = this.slots.getItem(1); - if (activeOffer.take(item, item1) || activeOffer.take(item1, item)) { -- this.merchant.notifyTrade(activeOffer); -+ this.merchant.processTrade(activeOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent + if (offer != null) { + ItemStack buyA = this.slots.getItem(0); + ItemStack buyB = this.slots.getItem(1); + if (offer.take(buyA, buyB) || offer.take(buyB, buyA)) { +- this.merchant.notifyTrade(offer); ++ this.merchant.processTrade(offer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent player.awardStat(Stats.TRADED_WITH_VILLAGER); - this.slots.setItem(0, item); - this.slots.setItem(1, item1); + this.slots.setItem(0, buyA); + this.slots.setItem(1, buyB); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/PlayerEnderChestContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/PlayerEnderChestContainer.java.patch index e41f6d341dc6..1cb0ed3ae49c 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/PlayerEnderChestContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/PlayerEnderChestContainer.java.patch @@ -25,4 +25,4 @@ + // CraftBukkit end } - public void setActiveChest(EnderChestBlockEntity enderChestBlockEntity) { + public void setActiveChest(final EnderChestBlockEntity activeChest) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch index 959b6d3d5e7e..e545b51623ec 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ResultSlot.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/inventory/ResultSlot.java +++ b/net/minecraft/world/inventory/ResultSlot.java @@ -39,6 +_,11 @@ - protected void onQuickCraft(ItemStack stack, int amount) { - this.removeCount += amount; - this.checkTakeAchievements(stack); + protected void onQuickCraft(final ItemStack picked, final int count) { + this.removeCount += count; + this.checkTakeAchievements(picked); + // Paper start - add ItemCraftedEvent -+ if (!stack.isEmpty()) { -+ new io.papermc.paper.event.inventory.ItemCraftedEvent((org.bukkit.entity.Player) this.player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack)).callEvent(); ++ if (!picked.isEmpty()) { ++ new io.papermc.paper.event.inventory.ItemCraftedEvent((org.bukkit.entity.Player) this.player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(picked)).callEvent(); + } + // Paper end - add ItemCraftedEvent } @Override @@ -72,7 +_,7 @@ - private NonNullList getRemainingItems(CraftingInput input, Level level) { + private NonNullList getRemainingItems(final CraftingInput input, final Level level) { return level instanceof ServerLevel serverLevel ? serverLevel.recipeAccess() - .getRecipeFor(RecipeType.CRAFTING, input, serverLevel) @@ -24,12 +24,12 @@ @@ -80,6 +_,11 @@ @Override - public void onTake(Player player, ItemStack stack) { + public void onTake(final Player player, final ItemStack carried) { + // Paper start - add ItemCraftedEvent -+ if (!stack.isEmpty()) { -+ new io.papermc.paper.event.inventory.ItemCraftedEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack)).callEvent(); ++ if (!carried.isEmpty()) { ++ new io.papermc.paper.event.inventory.ItemCraftedEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(carried)).callEvent(); + } + // Paper end - add ItemCraftedEvent - this.checkTakeAchievements(stack); - CraftingInput.Positioned positionedCraftInput = this.craftSlots.asPositionedCraftInput(); - CraftingInput craftingInput = positionedCraftInput.input(); + this.checkTakeAchievements(carried); + CraftingInput.Positioned positionedRecipe = this.craftSlots.asPositionedCraftInput(); + CraftingInput input = positionedRecipe.input(); diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ShulkerBoxMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ShulkerBoxMenu.java.patch index d5208fa9c81d..96369001f045 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ShulkerBoxMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ShulkerBoxMenu.java.patch @@ -5,7 +5,7 @@ private static final int CONTAINER_SIZE = 27; private final Container container; + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftInventoryView view; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftInventoryView view; + private final Inventory inventory; + + @Override @@ -24,22 +24,22 @@ + } + // CraftBukkit end - public ShulkerBoxMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, new SimpleContainer(27)); + public ShulkerBoxMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, new SimpleContainer(27)); @@ -18,7 +_,8 @@ super(MenuType.SHULKER_BOX, containerId); checkContainerSize(container, 27); this.container = container; -- container.startOpen(playerInventory.player); -+ this.inventory = playerInventory; // CraftBukkit -+ // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens - int i = 3; - int i1 = 9; +- container.startOpen(inventory.player); ++ this.inventory = inventory; // CraftBukkit ++ // container.startOpen(inventory.player); // Paper - don't startOpen until menu actually opens + int rows = 3; + int columns = 9; @@ -33,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return this.container.stillValid(player); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/SmithingMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/SmithingMenu.java.patch index afdbf864d4af..f768177b4717 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/SmithingMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/SmithingMenu.java.patch @@ -8,28 +8,28 @@ + private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity; + // CraftBukkit end - public SmithingMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); -@@ -100,6 +_,7 @@ - if (this.level instanceof ServerLevel) { - boolean flag = this.getSlot(0).hasItem() && this.getSlot(1).hasItem() && this.getSlot(2).hasItem() && !this.getSlot(this.getResultSlot()).hasItem(); - this.hasRecipeError.set(flag ? 1 : 0); + public SmithingMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); +@@ -103,6 +_,7 @@ + && this.getSlot(2).hasItem() + && !this.getSlot(this.getResultSlot()).hasItem(); + this.hasRecipeError.set(hasRecipeError ? 1 : 0); + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } } -@@ -116,7 +_,9 @@ - recipeFor.ifPresentOrElse(recipe -> { - ItemStack itemStack = recipe.value().assemble(smithingRecipeInput, this.level.registryAccess()); +@@ -119,7 +_,9 @@ + foundRecipe.ifPresentOrElse(recipe -> { + ItemStack result = recipe.value().assemble(input); this.resultSlots.setRecipeUsed((RecipeHolder)recipe); -- this.resultSlots.setItem(0, itemStack); +- this.resultSlots.setItem(0, result); + // CraftBukkit start -+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareSmithingEvent(this.getBukkitView(), itemStack); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareSmithingEvent(this.getBukkitView(), result); + // CraftBukkit end }, () -> { this.resultSlots.setRecipeUsed(null); this.resultSlots.setItem(0, ItemStack.EMPTY); -@@ -138,4 +_,18 @@ +@@ -141,4 +_,18 @@ public boolean hasRecipeError() { return this.hasRecipeError.get() > 0; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch index f0262737cac7..8513d6e3f342 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch @@ -1,37 +1,42 @@ --- a/net/minecraft/world/inventory/StonecutterMenu.java +++ b/net/minecraft/world/inventory/StonecutterMenu.java -@@ -25,7 +_,7 @@ +@@ -26,7 +_,7 @@ private static final int USE_ROW_SLOT_START = 29; private static final int USE_ROW_SLOT_END = 38; private final ContainerLevelAccess access; -- final DataSlot selectedRecipeIndex = DataSlot.standalone(); -+ final DataSlot selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent +- private final DataSlot selectedRecipeIndex = DataSlot.standalone(); ++ private final DataSlot selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent private final Level level; private SelectableRecipe.SingleInputSet recipesForInput = SelectableRecipe.SingleInputSet.empty(); private ItemStack input = ItemStack.EMPTY; -@@ -33,15 +_,23 @@ +@@ -34,19 +_,23 @@ final Slot inputSlot; final Slot resultSlot; - Runnable slotUpdateListener = () -> {}; + private Runnable slotUpdateListener = () -> {}; - public final Container container = new SimpleContainer(1) { +- { +- Objects.requireNonNull(StonecutterMenu.this); +- } +- - @Override - public void setChanged() { - super.setChanged(); - StonecutterMenu.this.slotsChanged(this); - StonecutterMenu.this.slotUpdateListener.run(); +- } +- }; +- private final ResultContainer resultContainer = new ResultContainer(); + public final Container container; // Paper - Add missing InventoryHolders - move down -+ final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down ++ private final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.view.CraftStonecutterView view = null; ++ private org.bukkit.craftbukkit.inventory.view.@org.jspecify.annotations.Nullable CraftStonecutterView view = null; + private final org.bukkit.entity.Player player; + + @Override + public org.bukkit.craftbukkit.inventory.view.CraftStonecutterView getBukkitView() { + if (this.view != null) { + return this.view; - } -- }; -- final ResultContainer resultContainer = new ResultContainer(); ++ } + + org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter(this.container, this.resultContainer); + this.view = new org.bukkit.craftbukkit.inventory.view.CraftStonecutterView(this.player, inventory, this); @@ -39,12 +44,12 @@ + } + // CraftBukkit end - public StonecutterMenu(int containerId, Inventory playerInventory) { - this(containerId, playerInventory, ContainerLevelAccess.NULL); -@@ -51,6 +_,23 @@ + public StonecutterMenu(final int containerId, final Inventory inventory) { + this(containerId, inventory, ContainerLevelAccess.NULL); +@@ -56,6 +_,23 @@ super(MenuType.STONECUTTER, containerId); this.access = access; - this.level = playerInventory.player.level(); + this.level = inventory.player.level(); + // Paper start + this.container = new SimpleContainer(this.createBlockHolder(access), 1) { // Paper - Add missing InventoryHolders + @Override @@ -64,35 +69,35 @@ + // Paper end this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33)); this.resultSlot = this.addSlot(new Slot(this.resultContainer, 1, 143, 33) { - @Override -@@ -83,6 +_,7 @@ + { +@@ -92,6 +_,7 @@ }); - this.addStandardInventorySlots(playerInventory, 8, 84); + this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlot(this.selectedRecipeIndex); -+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit ++ this.player = (org.bukkit.entity.Player) inventory.player.getBukkitEntity(); // CraftBukkit } public int getSelectedRecipeIndex() { -@@ -103,6 +_,7 @@ +@@ -112,6 +_,7 @@ @Override - public boolean stillValid(Player player) { + public boolean stillValid(final Player player) { + if (!this.checkReachable) return true; // CraftBukkit return stillValid(this.access, player, Blocks.STONECUTTER); } -@@ -112,8 +_,34 @@ +@@ -121,8 +_,34 @@ return false; } else { - if (this.isValidRecipeIndex(id)) { -- this.selectedRecipeIndex.set(id); -- this.setupResultSlot(id); + if (this.isValidRecipeIndex(buttonId)) { +- this.selectedRecipeIndex.set(buttonId); +- this.setupResultSlot(buttonId); + // Paper start - Add PlayerStonecutterRecipeSelectEvent -+ int recipeIndex = id; ++ int recipeIndex = buttonId; + this.selectedRecipeIndex.set(recipeIndex); + this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed -+ paperEventBlock: if (this.isValidRecipeIndex(id)) { -+ final Optional> recipe = this.recipesForInput.entries().get(id).recipe().recipe(); ++ paperEventBlock: if (this.isValidRecipeIndex(buttonId)) { ++ final Optional> recipe = this.recipesForInput.entries().get(buttonId).recipe().recipe(); + if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break. + + io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe()); @@ -118,11 +123,11 @@ } return true; -@@ -131,6 +_,7 @@ - this.input = item.copy(); - this.setupRecipeList(item); +@@ -140,6 +_,7 @@ + this.input = input.copy(); + this.setupRecipeList(input); } + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent } - private void setupRecipeList(ItemStack stack) { + private void setupRecipeList(final ItemStack item) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch index cded5ee713a4..0b201017d0e8 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/TransientCraftingContainer.java.patch @@ -32,7 +32,7 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.inventory.InventoryHolder getOwner() { ++ public org.bukkit.inventory.@org.jspecify.annotations.Nullable InventoryHolder getOwner() { + return (this.owner == null) ? null : this.owner.getBukkitEntity(); + } + @@ -68,6 +68,6 @@ + } + // CraftBukkit end + - public TransientCraftingContainer(AbstractContainerMenu menu, int width, int height) { + public TransientCraftingContainer(final AbstractContainerMenu menu, final int width, final int height) { this(menu, width, height, NonNullList.withSize(width * height, ItemStack.EMPTY)); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch index fe9ce9ce0727..2d44e2ce4371 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch @@ -2,14 +2,14 @@ +++ b/net/minecraft/world/item/ArmorStandItem.java @@ -45,6 +_,12 @@ - float f = Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F; - armorStand.snapTo(armorStand.getX(), armorStand.getY(), armorStand.getZ(), f, 0.0F); + float yRot = Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F; + entity.snapTo(entity.getX(), entity.getY(), entity.getZ(), yRot, 0.0F); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, armorStand).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entity).isCancelled()) { + if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end - serverLevel.addFreshEntityWithPassengers(armorStand); - level.playSound( - null, armorStand.getX(), armorStand.getY(), armorStand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F + serverLevel.addFreshEntityWithPassengers(entity); + level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); + entity.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch index cb0c66dc7f0f..167b36275867 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch @@ -5,10 +5,10 @@ } else { ItemStack itemInHand = context.getItemInHand(); + // Paper start - EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, optional.get())) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newBlock.get())) { + return InteractionResult.PASS; + } + // Paper end if (player instanceof ServerPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, clickedPos, itemInHand); + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, pos, itemInHand); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch index 52cf1527e917..b528d26d3d34 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch @@ -1,83 +1,75 @@ --- a/net/minecraft/world/item/BlockItem.java +++ b/net/minecraft/world/item/BlockItem.java -@@ -57,6 +_,14 @@ +@@ -56,6 +_,7 @@ return InteractionResult.FAIL; } else { - BlockState placementState = this.getPlacementState(blockPlaceContext); -+ // CraftBukkit start - special case for handling block placement with water lilies and snow buckets -+ org.bukkit.block.BlockState bukkitState = null; -+ if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) { -+ bukkitState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockPlaceContext.getLevel(), blockPlaceContext.getClickedPos()); -+ } -+ final org.bukkit.block.BlockState oldBukkitState = bukkitState != null ? bukkitState : org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockPlaceContext.getLevel(), blockPlaceContext.getClickedPos()); // Paper - Reset placed block on exception -+ // CraftBukkit end -+ + BlockState placementState = this.getPlacementState(updatedPlaceContext); ++ final org.bukkit.block.BlockState previousState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(updatedPlaceContext.getLevel(), updatedPlaceContext.getClickedPos()); // Paper - Reset placed block on exception if (placementState == null) { return InteractionResult.FAIL; - } else if (!this.placeBlock(blockPlaceContext, placementState)) { -@@ -69,15 +_,39 @@ - BlockState blockState = level.getBlockState(clickedPos); - if (blockState.is(placementState.getBlock())) { - blockState = this.updateBlockStateFromTag(clickedPos, level, itemInHand, blockState); + } else if (!this.placeBlock(updatedPlaceContext, placementState)) { +@@ -68,21 +_,45 @@ + BlockState placedState = level.getBlockState(pos); + if (placedState.is(placementState.getBlock())) { + placedState = this.updateBlockStateFromTag(pos, level, itemStack, placedState); + // Paper start - Reset placed block on exception + try { - this.updateCustomBlockEntityTag(clickedPos, level, player, itemInHand, blockState); - updateBlockEntityComponents(level, clickedPos, itemInHand); + this.updateCustomBlockEntityTag(pos, level, player, itemStack, placedState); + updateBlockEntityComponents(level, pos, itemStack); + } catch (Exception ex) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) oldBukkitState).revertPlace(); ++ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); + if (player instanceof ServerPlayer serverPlayer) { -+ org.apache.logging.log4j.LogManager.getLogger().error("Player {} tried placing invalid block", player.getScoreboardName(), ex); -+ serverPlayer.getBukkitEntity().kickPlayer("Packet processing error"); ++ net.minecraft.server.MinecraftServer.LOGGER.warn("Player {} tried placing invalid block", player.getScoreboardName(), ex); ++ serverPlayer.connection.disconnect(net.minecraft.network.chat.Component.literal("Packet processing error")); + return InteractionResult.FAIL; + } + throw ex; // Rethrow exception if not placed by a player + } + // Paper end - Reset placed block on exception - blockState.getBlock().setPlacedBy(level, clickedPos, blockState, player, itemInHand); -+ // CraftBukkit start -+ if (bukkitState != null) { -+ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((net.minecraft.server.level.ServerLevel) level, player, blockPlaceContext.getHand(), bukkitState, clickedPos); -+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) bukkitState).revertPlace(); + placedState.getBlock().setPlacedBy(level, pos, placedState, player, itemStack); ++ // CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets ++ if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) { ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((net.minecraft.server.level.ServerLevel) level, player, updatedPlaceContext.getHand(), previousState, pos); ++ if (placeEvent.isCancelled() || !placeEvent.canBuild()) { ++ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); + -+ player.containerMenu.forceHeldSlot(blockPlaceContext.getHand()); ++ player.containerMenu.forceHeldSlot(updatedPlaceContext.getHand()); + return InteractionResult.FAIL; + } + } + // CraftBukkit end if (player instanceof ServerPlayer) { - CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, clickedPos, itemInHand); + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, pos, itemStack); } } - SoundType soundType = blockState.getSoundType(); + SoundType soundType = placedState.getSoundType(); + if (player == null) // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker) level.playSound( - player, - clickedPos, -@@ -88,7 +_,7 @@ + player, pos, this.getPlaceSound(placedState), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F ); - level.gameEvent(GameEvent.BLOCK_PLACE, clickedPos, GameEvent.Context.of(player, blockState)); - itemInHand.consume(1, player); + level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(player, placedState)); + itemStack.consume(1, player); - return InteractionResult.SUCCESS; -+ return InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(clickedPos.immutable())); // Paper - track placed block position from block item ++ return InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(pos.immutable())); // Paper - track placed block position from block item } } } -@@ -135,8 +_,19 @@ +@@ -131,8 +_,20 @@ - protected boolean canPlace(BlockPlaceContext context, BlockState state) { + protected boolean canPlace(final BlockPlaceContext context, final BlockState stateForPlacement) { Player player = context.getPlayer(); -- return (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) -- && context.getLevel().isUnobstructed(state, context.getClickedPos(), CollisionContext.placementContext(player)); +- return (!this.mustSurvive() || stateForPlacement.canSurvive(context.getLevel(), context.getClickedPos())) +- && context.getLevel().isUnobstructed(stateForPlacement, context.getClickedPos(), CollisionContext.placementContext(player)); + // CraftBukkit start + Level world = context.getLevel(); // Paper - Cancel hit for vanished players -+ boolean canBuild = (!this.mustSurvive() || state.canSurvive(world, context.getClickedPos())) && world.checkEntityCollision(state, player, CollisionContext.placementContext(player), context.getClickedPos(), true); // Paper - Cancel hit for vanished players ++ boolean canBuild = (!this.mustSurvive() || stateForPlacement.canSurvive(world, context.getClickedPos())) ++ && world.checkEntityCollision(stateForPlacement, player, CollisionContext.placementContext(player), context.getClickedPos(), true); // Paper - Cancel hit for vanished players + org.bukkit.entity.Player bukkitPlayer = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null; + + org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(world, context.getClickedPos()), bukkitPlayer, -+ org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(state), canBuild, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand()) ++ stateForPlacement.asBlockData(), canBuild, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand()) + ); + world.getCraftServer().getPluginManager().callEvent(event); + @@ -86,12 +78,12 @@ } protected boolean mustSurvive() { -@@ -160,7 +_,7 @@ +@@ -156,7 +_,7 @@ return false; } - if (!type.onlyOpCanSetNbt() || player != null && player.canUseGameMasterBlocks()) { + if (!type.onlyOpCanSetNbt() || player != null && (player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place")))) { // Spigot - add permission - return typedEntityData.loadInto(blockEntity, level.registryAccess()); + return customData.loadInto(blockEntity, level.registryAccess()); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch index ebd369c1cf4c..2c9c26a6af7c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch @@ -2,25 +2,25 @@ +++ b/net/minecraft/world/item/BoatItem.java @@ -30,7 +_,7 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); -- HitResult playerPovHitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY); -+ net.minecraft.world.phys.BlockHitResult playerPovHitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY); // Paper - if (playerPovHitResult.getType() == HitResult.Type.MISS) { + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); +- HitResult hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY); ++ net.minecraft.world.phys.BlockHitResult hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY); // Paper + if (hitResult.getType() == HitResult.Type.MISS) { return InteractionResult.PASS; } else { @@ -51,6 +_,13 @@ } - if (playerPovHitResult.getType() == HitResult.Type.BLOCK) { + if (hitResult.getType() == HitResult.Type.BLOCK) { + // CraftBukkit start - Boat placement -+ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, playerPovHitResult.getBlockPos(), playerPovHitResult.getDirection(), itemInHand, false, hand, playerPovHitResult.getLocation()); ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, hitResult.getBlockPos(), hitResult.getDirection(), itemStack, false, hand, hitResult.getLocation()); + + if (event.isCancelled()) { + return InteractionResult.PASS; + } + // CraftBukkit end - AbstractBoat boat = this.getBoat(level, playerPovHitResult, itemInHand, player); + AbstractBoat boat = this.getBoat(level, hitResult, itemStack, player); if (boat == null) { return InteractionResult.FAIL; @@ -60,7 +_,15 @@ @@ -29,7 +29,7 @@ if (!level.isClientSide()) { - level.addFreshEntity(boat); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(level, playerPovHitResult.getBlockPos(), player.getDirection(), player, boat, hand).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(level, hitResult.getBlockPos(), player.getDirection(), player, boat, hand).isCancelled()) { + return InteractionResult.FAIL; + } + @@ -37,6 +37,6 @@ + return InteractionResult.PASS; + } + // CraftBukkit end - level.gameEvent(player, GameEvent.ENTITY_PLACE, playerPovHitResult.getLocation()); - itemInHand.consume(1, player); + level.gameEvent(player, GameEvent.ENTITY_PLACE, hitResult.getLocation()); + itemStack.consume(1, player); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BoneMealItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BoneMealItem.java.patch index 71411b0ac61e..bdae8c85b266 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BoneMealItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BoneMealItem.java.patch @@ -3,29 +3,29 @@ @@ -35,13 +_,18 @@ @Override - public InteractionResult useOn(UseOnContext context) { + public InteractionResult useOn(final UseOnContext context) { + // CraftBukkit start - extract bonemeal application logic to separate, static method + return BoneMealItem.applyBonemeal(context); + } -+ public static InteractionResult applyBonemeal(UseOnContext context) { ++ public static InteractionResult applyBonemeal(final UseOnContext context) { + // CraftBukkit end Level level = context.getLevel(); - BlockPos clickedPos = context.getClickedPos(); - BlockPos blockPos = clickedPos.relative(context.getClickedFace()); - ItemStack itemInHand = context.getItemInHand(); - if (growCrop(itemInHand, level, clickedPos)) { + BlockPos pos = context.getClickedPos(); + BlockPos relative = pos.relative(context.getClickedFace()); + ItemStack boneMealStack = context.getItemInHand(); + if (growCrop(boneMealStack, level, pos)) { if (!level.isClientSide()) { -- itemInHand.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); -+ if (context.getPlayer() != null) itemInHand.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518 - level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, clickedPos, 15); - } - -@@ -51,7 +_,7 @@ - boolean isFaceSturdy = blockState.isFaceSturdy(level, clickedPos, context.getClickedFace()); - if (isFaceSturdy && growWaterPlant(itemInHand, level, blockPos, context.getClickedFace())) { +- boneMealStack.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); ++ if (context.getPlayer() != null) boneMealStack.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518 + level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, pos, 15); + return InteractionResult.SUCCESS_SERVER; + } else { +@@ -52,7 +_,7 @@ + boolean solidBlockFace = clickedState.isFaceSturdy(level, pos, context.getClickedFace()); + if (solidBlockFace && growWaterPlant(boneMealStack, level, relative, context.getClickedFace())) { if (!level.isClientSide()) { -- itemInHand.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); -+ if (context.getPlayer() != null) itemInHand.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518 - level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, blockPos, 15); +- boneMealStack.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); ++ if (context.getPlayer() != null) boneMealStack.causeUseVibration(context.getPlayer(), GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518 + level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, relative, 15); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch index 52bde9e226af..6fde4d9f0c9e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/item/BowItem.java @@ -38,7 +_,7 @@ } else { - List list = draw(stack, projectile, player); - if (level instanceof ServerLevel serverLevel && !list.isEmpty()) { -- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null); -+ this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null, powerForTime); // Paper - Pass draw strength + List firedProjectiles = draw(itemStack, projectile, player); + if (level instanceof ServerLevel serverLevel && !firedProjectiles.isEmpty()) { +- this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null); ++ this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null, pow); // Paper - Pass draw strength } level.playSound( diff --git a/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch index 534428c9d894..bcc7764e4ea5 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch @@ -1,50 +1,50 @@ --- a/net/minecraft/world/item/BucketItem.java +++ b/net/minecraft/world/item/BucketItem.java -@@ -31,6 +_,7 @@ +@@ -32,6 +_,7 @@ import org.jspecify.annotations.Nullable; public class BucketItem extends Item implements DispensibleContainerItem { + private static @Nullable ItemStack itemLeftInHandAfterPlayerBucketEmptyEvent = null; // Paper - Fix PlayerBucketEmptyEvent result itemstack public final Fluid content; - public BucketItem(Fluid content, Item.Properties properties) { -@@ -57,12 +_,22 @@ + public BucketItem(final Fluid content, final Item.Properties properties) { +@@ -56,12 +_,22 @@ } else if (this.content == Fluids.EMPTY) { - BlockState blockState = level.getBlockState(blockPos); - if (blockState.getBlock() instanceof BucketPickup bucketPickup) { + BlockState blockState = level.getBlockState(pos); + if (blockState.getBlock() instanceof BucketPickup bucketPickupBlock) { + // CraftBukkit start -+ ItemStack dummyFluid = bucketPickup.pickupBlock(player, org.bukkit.craftbukkit.util.DummyGeneratorAccess.INSTANCE, blockPos, blockState); ++ ItemStack dummyFluid = bucketPickupBlock.pickupBlock(player, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, pos, blockState); + if (dummyFluid.isEmpty()) return InteractionResult.FAIL; // Don't fire event if the bucket won't be filled. -+ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, blockPos, blockPos, playerPovHitResult.getDirection(), itemInHand, dummyFluid.getItem(), hand); ++ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitResult.getDirection(), itemStack, dummyFluid.getItem(), hand); + + if (event.isCancelled()) { + player.containerMenu.sendAllDataToRemote(); // SPIGOT-4541 + return InteractionResult.FAIL; + } + // CraftBukkit end - ItemStack itemStack = bucketPickup.pickupBlock(player, level, blockPos, blockState); - if (!itemStack.isEmpty()) { + ItemStack taken = bucketPickupBlock.pickupBlock(player, level, pos, blockState); + if (!taken.isEmpty()) { player.awardStat(Stats.ITEM_USED.get(this)); - bucketPickup.getPickupSound().ifPresent(sound -> player.playSound(sound, 1.0F, 1.0F)); - level.gameEvent(player, GameEvent.FLUID_PICKUP, blockPos); -- ItemStack itemStack1 = ItemUtils.createFilledResult(itemInHand, player, itemStack); -+ ItemStack itemStack1 = ItemUtils.createFilledResult(itemInHand, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + bucketPickupBlock.getPickupSound().ifPresent(soundEvent -> player.playSound(soundEvent, 1.0F, 1.0F)); + level.gameEvent(player, GameEvent.FLUID_PICKUP, pos); +- ItemStack result = ItemUtils.createFilledResult(itemStack, player, taken); ++ ItemStack result = ItemUtils.createFilledResult(itemStack, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit if (!level.isClientSide()) { - CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, itemStack); + CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, taken); } -@@ -75,7 +_,7 @@ +@@ -74,7 +_,7 @@ } else { - BlockState blockState = level.getBlockState(blockPos); - BlockPos blockPos2 = blockState.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? blockPos : blockPos1; -- if (this.emptyContents(player, level, blockPos2, playerPovHitResult)) { -+ if (this.emptyContents(player, level, blockPos2, playerPovHitResult, playerPovHitResult.getDirection(), blockPos, itemInHand, hand)) { // CraftBukkit - this.checkExtraContent(player, level, itemInHand, blockPos2); + BlockState clicked = level.getBlockState(pos); + BlockPos placePos = clicked.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? pos : directionOffsetPos; +- if (this.emptyContents(player, level, placePos, hitResult)) { ++ if (this.emptyContents(player, level, placePos, hitResult, hitResult.getDirection(), pos, itemStack, hand)) { // CraftBukkit + this.checkExtraContent(player, level, itemStack, placePos); if (player instanceof ServerPlayer) { - CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, blockPos2, itemInHand); -@@ -92,6 +_,13 @@ + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, placePos, itemStack); +@@ -91,6 +_,13 @@ } - public static ItemStack getEmptySuccessItem(ItemStack bucketStack, Player player) { + public static ItemStack getEmptySuccessItem(final ItemStack itemStack, final Player player) { + // Paper start - Fix PlayerBucketEmptyEvent result itemstack + if (itemLeftInHandAfterPlayerBucketEmptyEvent != null) { + ItemStack itemInHand = itemLeftInHandAfterPlayerBucketEmptyEvent; @@ -52,29 +52,29 @@ + return itemInHand; + } + // Paper end - Fix PlayerBucketEmptyEvent result itemstack - return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : bucketStack; + return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : itemStack; } -@@ -101,6 +_,12 @@ +@@ -100,6 +_,12 @@ @Override - public boolean emptyContents(@Nullable LivingEntity entity, Level level, BlockPos pos, @Nullable BlockHitResult hitResult) { + public boolean emptyContents(final @Nullable LivingEntity user, final Level level, final BlockPos pos, final @Nullable BlockHitResult hitResult) { + // CraftBukkit start -+ return this.emptyContents(entity, level, pos, hitResult, null, null, null, InteractionHand.MAIN_HAND); ++ return this.emptyContents(user, level, pos, hitResult, null, null, null, InteractionHand.MAIN_HAND); + } + -+ public boolean emptyContents(@Nullable LivingEntity entity, Level level, BlockPos pos, @Nullable BlockHitResult hitResult, Direction direction, BlockPos clicked, ItemStack itemstack, InteractionHand hand) { ++ public boolean emptyContents(final @Nullable LivingEntity user, final Level level, final BlockPos pos, final @Nullable BlockHitResult hitResult, final Direction direction, final BlockPos clicked, final ItemStack itemStack, final InteractionHand hand) { + // CraftBukkit end if (!(this.content instanceof FlowingFluid flowingFluid)) { return false; } else { -@@ -112,8 +_,18 @@ - || block instanceof LiquidBlockContainer liquidBlockContainer - && liquidBlockContainer.canPlaceLiquid(entity, level, pos, blockState, this.content); - boolean flag2 = blockState.isAir() || flag1 && (!flag || hitResult == null); +@@ -110,8 +_,18 @@ + boolean placeLiquid = mayReplace + || block instanceof LiquidBlockContainer container && container.canPlaceLiquid(user, level, pos, blockState, this.content); + boolean canPlaceFluidInsideBlock = blockState.isAir() || placeLiquid && (!shiftKeyDown || hitResult == null); + // CraftBukkit start -+ if (flag2 && entity instanceof Player player) { -+ org.bukkit.event.player.PlayerBucketEmptyEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent(level, player, pos, clicked, direction, itemstack, hand); ++ if (canPlaceFluidInsideBlock && user instanceof Player player) { ++ org.bukkit.event.player.PlayerBucketEmptyEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent(level, player, pos, clicked, direction, itemStack, hand); + if (event.isCancelled()) { + player.containerMenu.sendAllDataToRemote(); // SPIGOT-4541 + return false; @@ -82,9 +82,9 @@ + itemLeftInHandAfterPlayerBucketEmptyEvent = event.getItemStack() != null ? event.getItemStack().equals(org.bukkit.craftbukkit.inventory.CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.BUCKET)) ? null : org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; // Paper - Fix PlayerBucketEmptyEvent result itemstack + } + // CraftBukkit end - if (!flag2) { -- return hitResult != null && this.emptyContents(entity, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null); -+ return hitResult != null && this.emptyContents(entity, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null, direction, clicked, itemstack, hand); // CraftBukkit + if (!canPlaceFluidInsideBlock) { +- return hitResult != null && this.emptyContents(user, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null); ++ return hitResult != null && this.emptyContents(user, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null, direction, clicked, itemStack, hand); // CraftBukkit } else if (level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos) && this.content.is(FluidTags.WATER)) { int x = pos.getX(); int y = pos.getY(); diff --git a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch index a68d47e47dca..de368c09a9c5 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch @@ -1,56 +1,56 @@ --- a/net/minecraft/world/item/CrossbowItem.java +++ b/net/minecraft/world/item/CrossbowItem.java @@ -88,8 +_,15 @@ - return getPowerForTime(i, stack, entity) >= 1.0F && isCharged(stack); + return getPowerForTime(timeHeld, itemStack, entity) >= 1.0F && isCharged(itemStack); } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add EntityLoadCrossbowEvent - private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack) { -- List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter); + private static boolean tryLoadProjectiles(final LivingEntity shooter, final ItemStack heldItem) { +- List drawn = draw(heldItem, shooter.getProjectile(heldItem), shooter); + // Paper start - Add EntityLoadCrossbowEvent -+ return tryLoadProjectiles(shooter, crossbowStack, true); ++ return tryLoadProjectiles(shooter, heldItem, true); + } + -+ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack, boolean consume) { -+ List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume); ++ private static boolean tryLoadProjectiles(final LivingEntity shooter, final ItemStack heldItem, final boolean consume) { ++ List drawn = draw(heldItem, shooter.getProjectile(heldItem), shooter, consume); + // Paper end - Add EntityLoadCrossbowEvent - if (!list.isEmpty()) { - crossbowStack.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); + if (!drawn.isEmpty()) { + heldItem.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.ofNonEmpty(drawn)); return true; -@@ -141,7 +_,11 @@ - @Override - protected Projectile createProjectile(Level level, LivingEntity shooter, ItemStack weapon, ItemStack ammo, boolean isCrit) { - if (ammo.is(Items.FIREWORK_ROCKET)) { -- return new FireworkRocketEntity(level, ammo, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true); +@@ -159,7 +_,11 @@ + final Level level, final LivingEntity shooter, final ItemStack heldItem, final ItemStack projectile, final boolean isCrit + ) { + if (projectile.is(Items.FIREWORK_ROCKET)) { +- return new FireworkRocketEntity(level, projectile, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true); + // Paper start -+ FireworkRocketEntity entity = new FireworkRocketEntity(level, ammo, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true); ++ FireworkRocketEntity entity = new FireworkRocketEntity(level, projectile, shooter, shooter.getX(), shooter.getEyeY() - 0.15F, shooter.getZ(), true); + entity.spawningEntity = shooter.getUUID(); // Paper + return entity; + // Paper end } else { - Projectile projectile = super.createProjectile(level, shooter, weapon, ammo, isCrit); - if (projectile instanceof AbstractArrow abstractArrow) { -@@ -163,7 +_,7 @@ + Projectile projectileEntity = super.createProjectile(level, shooter, heldItem, projectile, isCrit); + if (projectileEntity instanceof AbstractArrow arrow) { +@@ -187,7 +_,7 @@ if (level instanceof ServerLevel serverLevel) { - ChargedProjectiles chargedProjectiles = weapon.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY); - if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { -- this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target); -+ this.shoot(serverLevel, shooter, hand, weapon, chargedProjectiles.getItems(), velocity, inaccuracy, shooter instanceof Player, target, 1); // Paper - Pass draw strength - if (shooter instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.SHOT_CROSSBOW.trigger(serverPlayer, weapon); - serverPlayer.awardStat(Stats.ITEM_USED.get(weapon.getItem())); -@@ -211,7 +_,13 @@ - ); + ChargedProjectiles charged = weapon.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY); + if (charged != null && !charged.isEmpty()) { +- this.shoot(serverLevel, shooter, hand, weapon, charged.itemCopies(), power, uncertainty, shooter instanceof Player, targetOverride); ++ this.shoot(serverLevel, shooter, hand, weapon, charged.itemCopies(), power, uncertainty, shooter instanceof Player, targetOverride, 1.0F); // Paper - Pass draw strength + if (shooter instanceof ServerPlayer player) { + CriteriaTriggers.SHOT_CROSSBOW.trigger(player, weapon); + player.awardStat(Stats.ITEM_USED.get(weapon.getItem())); +@@ -227,7 +_,13 @@ + .ifPresent(sound -> level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), sound.value(), SoundSource.PLAYERS, 0.5F, 1.0F)); } -- if (f >= 1.0F && !isCharged(stack) && tryLoadProjectiles(livingEntity, stack)) { -+ if (f >= 1.0F && !isCharged(stack)) { +- if (tickPercent >= 1.0F && !isCharged(itemStack) && tryLoadProjectiles(entity, itemStack)) { ++ if (tickPercent >= 1.0F && !isCharged(itemStack)) { + // Paper start - Add EntityLoadCrossbowEvent -+ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(livingEntity.getBukkitLivingEntity(), stack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(livingEntity.getUsedItemHand())); -+ if (!event.callEvent() || !tryLoadProjectiles(livingEntity, stack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) { ++ final io.papermc.paper.event.entity.EntityLoadCrossbowEvent event = new io.papermc.paper.event.entity.EntityLoadCrossbowEvent(entity.getBukkitLivingEntity(), itemStack.asBukkitMirror(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(entity.getUsedItemHand())); ++ if (!event.callEvent() || !tryLoadProjectiles(entity, itemStack, event.shouldConsumeItem()) || !event.shouldConsumeItem()) { + return; + } + // Paper end - Add EntityLoadCrossbowEvent - chargingSounds.end() + sounds.end() .ifPresent( sound -> level.playSound( diff --git a/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch index affcf590be1f..77743d475147 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/DebugStickItem.java +++ b/net/minecraft/world/item/DebugStickItem.java -@@ -49,7 +_,7 @@ - } - - public boolean handleInteraction(Player player, BlockState stateClicked, LevelAccessor level, BlockPos pos, boolean shouldCycleState, ItemStack debugStack) { +@@ -51,7 +_,7 @@ + public boolean handleInteraction( + final ServerPlayer player, final BlockState state, final LevelAccessor level, final BlockPos pos, final boolean cycle, final ItemStack itemStackInHand + ) { - if (!player.canUseGameMasterBlocks()) { + if (!player.canUseGameMasterBlocks() && !(player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.debugstick")) && !player.getBukkitEntity().hasPermission("minecraft.debugstick.always")) { // Spigot return false; } else { - Holder blockHolder = stateClicked.getBlockHolder(); + Holder block = state.typeHolder(); diff --git a/paper-server/patches/sources/net/minecraft/world/item/DyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/DyeItem.java.patch index aac31da40df4..4347f67384dd 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/DyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/DyeItem.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/item/DyeItem.java +++ b/net/minecraft/world/item/DyeItem.java -@@ -27,7 +_,17 @@ - if (target instanceof Sheep sheep && sheep.isAlive() && !sheep.isSheared() && sheep.getColor() != this.dyeColor) { - sheep.level().playSound(player, sheep, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1.0F, 1.0F); - if (!player.level().isClientSide()) { -- sheep.setColor(this.dyeColor); -+ // CraftBukkit start -+ byte bColor = (byte) this.dyeColor.getId(); -+ org.bukkit.event.entity.SheepDyeWoolEvent event = new org.bukkit.event.entity.SheepDyeWoolEvent((org.bukkit.entity.Sheep) sheep.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData(bColor), (org.bukkit.entity.Player) player.getBukkitEntity()); -+ sheep.level().getCraftServer().getPluginManager().callEvent(event); +@@ -23,7 +_,17 @@ + if (dyeColor != null && sheep.getColor() != dyeColor) { + sheep.level().playSound(player, sheep, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1.0F, 1.0F); + if (!player.level().isClientSide()) { +- sheep.setColor(dyeColor); ++ // CraftBukkit start ++ byte bColor = (byte) dyeColor.getId(); ++ org.bukkit.event.entity.SheepDyeWoolEvent event = new org.bukkit.event.entity.SheepDyeWoolEvent((org.bukkit.entity.Sheep) sheep.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData(bColor), (org.bukkit.entity.Player) player.getBukkitEntity()); ++ sheep.level().getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } + -+ sheep.setColor(DyeColor.byId((byte) event.getColor().getWoolData())); -+ // CraftBukkit end - stack.shrink(1); - } ++ sheep.setColor(DyeColor.byId((byte) event.getColor().getWoolData())); ++ // CraftBukkit end + itemStack.shrink(1); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EggItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EggItem.java.patch index 936bc3448386..c04d7fd6a803 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EggItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EggItem.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/item/EggItem.java @@ -23,22 +_,35 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); - level.playSound( - null, - player.getX(), @@ -15,14 +15,14 @@ - 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F) - ); - if (level instanceof ServerLevel serverLevel) { -- Projectile.spawnProjectileFromRotation(ThrownEgg::new, serverLevel, itemInHand, player, 0.0F, 1.5F, 1.0F); +- Projectile.spawnProjectileFromRotation(ThrownEgg::new, serverLevel, itemStack, player, 0.0F, 1.5F, 1.0F); - } + // Paper start -+ final Projectile.Delayed thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, (ServerLevel) level, itemInHand, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F); -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity()); ++ final Projectile.Delayed thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, (ServerLevel) level, itemStack, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity()); + if (event.callEvent() && thrownEgg.attemptSpawn()) { + if (event.shouldConsume()) { -+ itemInHand.consume(1, player); ++ itemStack.consume(1, player); + } else { + player.containerMenu.forceHeldSlot(hand); + } @@ -40,7 +40,7 @@ + // Paper - move up - player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- itemStack.consume(1, player); + player.awardStat(Stats.ITEM_USED.get(this)); + // Paper start + } else { diff --git a/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch index 9cd8c1185b5c..bc25fbb2abdb 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/item/EmptyMapItem.java +++ b/net/minecraft/world/item/EmptyMapItem.java @@ -17,10 +_,16 @@ - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); if (level instanceof ServerLevel serverLevel) { -+ org.bukkit.inventory.ItemStack emptyMap = itemInHand.asBukkitCopy(); // Paper - PlayerMapFilledEvent - itemInHand.consume(1, player); ++ org.bukkit.inventory.ItemStack emptyMap = itemStack.asBukkitCopy(); // Paper - PlayerMapFilledEvent + itemStack.consume(1, player); player.awardStat(Stats.ITEM_USED.get(this)); serverLevel.playSound(null, player, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, player.getSoundSource(), 1.0F, 1.0F); - ItemStack itemStack = MapItem.create(serverLevel, player.getBlockX(), player.getBlockZ(), (byte)0, true, false); + ItemStack map = MapItem.create(serverLevel, player.getBlockX(), player.getBlockZ(), (byte)0, true, false); + // Paper start - PlayerMapFilledEvent -+ io.papermc.paper.event.player.PlayerMapFilledEvent event = new io.papermc.paper.event.player.PlayerMapFilledEvent((org.bukkit.entity.Player) player.getBukkitEntity(), emptyMap, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack)); ++ io.papermc.paper.event.player.PlayerMapFilledEvent event = new io.papermc.paper.event.player.PlayerMapFilledEvent((org.bukkit.entity.Player) player.getBukkitEntity(), emptyMap, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(map)); + event.callEvent(); -+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getCreatedMap()); ++ map = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getCreatedMap()); + // Paper end - PlayerMapFilledEvent - if (itemInHand.isEmpty()) { - return InteractionResult.SUCCESS.heldItemTransformedTo(itemStack); + if (itemStack.isEmpty()) { + return InteractionResult.SUCCESS.heldItemTransformedTo(map); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch index a82c58ec7624..3ec27164f56d 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch @@ -1,30 +1,21 @@ --- a/net/minecraft/world/item/EndCrystalItem.java +++ b/net/minecraft/world/item/EndCrystalItem.java -@@ -27,7 +_,7 @@ - if (!blockState.is(Blocks.OBSIDIAN) && !blockState.is(Blocks.BEDROCK)) { - return InteractionResult.FAIL; - } else { -- BlockPos blockPos = clickedPos.above(); -+ BlockPos blockPos = clickedPos.above(); final BlockPos aboveBlockPos = blockPos; // Paper - OBFHELPER - if (!level.isEmptyBlock(blockPos)) { - return InteractionResult.FAIL; - } else { @@ -41,11 +_,17 @@ if (level instanceof ServerLevel) { - EndCrystal endCrystal = new EndCrystal(level, d + 0.5, d1, d2 + 0.5); - endCrystal.setShowBottom(false); + EndCrystal crystal = new EndCrystal(level, x + 0.5, y, z + 0.5); + crystal.setShowBottom(false); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, endCrystal).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, crystal).isCancelled()) { + if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end - level.addFreshEntity(endCrystal); - level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, blockPos); - EndDragonFight dragonFight = ((ServerLevel)level).getDragonFight(); - if (dragonFight != null) { -- dragonFight.tryRespawn(); -+ dragonFight.tryRespawn(aboveBlockPos); // Paper - Perf: Do crystal-portal proximity check before entity lookup + level.addFreshEntity(crystal); + level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, above); + EnderDragonFight fight = ((ServerLevel)level).getDragonFight(); + if (fight != null) { +- fight.tryRespawn(); ++ fight.tryRespawn(above); // Paper - Perf: Do crystal-portal proximity check before entity lookup } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch index 8b88132b3f42..f5c54962a93a 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch @@ -3,15 +3,15 @@ @@ -44,6 +_,11 @@ return InteractionResult.SUCCESS; } else { - BlockState blockState1 = blockState.setValue(EndPortalFrameBlock.HAS_EYE, true); + BlockState newState = targetState.setValue(EndPortalFrameBlock.HAS_EYE, true); + // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), clickedPos, blockState1)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, newState)) { + return InteractionResult.PASS; + } + // Paper end - Block.pushEntitiesUp(blockState, blockState1, level, clickedPos); - level.setBlock(clickedPos, blockState1, Block.UPDATE_CLIENTS); - level.updateNeighbourForOutputSignal(clickedPos, Blocks.END_PORTAL_FRAME); + Block.pushEntitiesUp(targetState, newState, level, pos); + level.setBlock(pos, newState, Block.UPDATE_CLIENTS); + level.updateNeighbourForOutputSignal(pos, Blocks.END_PORTAL_FRAME); @@ -61,7 +_,27 @@ } } @@ -42,8 +42,8 @@ return InteractionResult.SUCCESS; @@ -91,7 +_,11 @@ - eyeOfEnder.setItem(itemInHand); - eyeOfEnder.signalTo(Vec3.atLowerCornerOf(blockPos)); + eyeOfEnder.setItem(itemStack); + eyeOfEnder.signalTo(Vec3.atLowerCornerOf(nearestMapFeature)); level.gameEvent(GameEvent.PROJECTILE_SHOOT, eyeOfEnder.position(), GameEvent.Context.of(player)); - level.addFreshEntity(eyeOfEnder); + // CraftBukkit start @@ -52,5 +52,5 @@ + } + // CraftBukkit end if (player instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.USED_ENDER_EYE.trigger(serverPlayer, blockPos); + CriteriaTriggers.USED_ENDER_EYE.trigger(serverPlayer, nearestMapFeature); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch index 28fbeb9fcae3..233d4a56fe41 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/item/EnderpearlItem.java @@ -21,22 +_,42 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); - level.playSound( - null, - player.getX(), @@ -15,14 +15,14 @@ - 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F) - ); if (level instanceof ServerLevel serverLevel) { -- Projectile.spawnProjectileFromRotation(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, PROJECTILE_SHOOT_POWER, 1.0F); +- Projectile.spawnProjectileFromRotation(ThrownEnderpearl::new, serverLevel, itemStack, player, 0.0F, 1.5F, 1.0F); + // CraftBukkit start + // Paper start - PlayerLaunchProjectileEvent -+ final Projectile.Delayed thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F); -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity()); ++ final Projectile.Delayed thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemStack, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity()); + if (event.callEvent() && thrownEnderpearl.attemptSpawn()) { + if (event.shouldConsume()) { -+ itemInHand.consume(1, player); ++ itemStack.consume(1, player); + } else { + player.containerMenu.forceHeldSlot(hand); + } @@ -41,7 +41,7 @@ + } else { + if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { + serverPlayer.deregisterEnderPearl(thrownEnderpearl.projectile()); -+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemInHand), 0)); // prevent visual desync of cooldown on the slot ++ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemStack), 0)); // prevent visual desync of cooldown on the slot + } + // Paper end - PlayerLaunchProjectileEvent + player.containerMenu.forceHeldSlot(hand); @@ -51,7 +51,7 @@ + // CraftBukkit end - player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- itemStack.consume(1, player); + // Paper - PlayerLaunchProjectileEvent - moved up return InteractionResult.SUCCESS; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ExperienceBottleItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ExperienceBottleItem.java.patch index eeafee1fb89e..7ca72e919df4 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ExperienceBottleItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ExperienceBottleItem.java.patch @@ -2,8 +2,8 @@ +++ b/net/minecraft/world/item/ExperienceBottleItem.java @@ -21,22 +_,37 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); - level.playSound( - null, - player.getX(), @@ -16,13 +16,13 @@ - ); + // Paper - PlayerLaunchProjectileEvent - moved down if (level instanceof ServerLevel serverLevel) { -- Projectile.spawnProjectileFromRotation(ThrownExperienceBottle::new, serverLevel, itemInHand, player, -20.0F, 0.7F, 1.0F); +- Projectile.spawnProjectileFromRotation(ThrownExperienceBottle::new, serverLevel, itemStack, player, -20.0F, 0.7F, 1.0F); + // Paper start - PlayerLaunchProjectileEvent -+ final Projectile.Delayed thrownExperienceBottle = Projectile.spawnProjectileFromRotationDelayed(ThrownExperienceBottle::new, serverLevel, itemInHand, player, -20.0F, 0.7F, 1.0F); -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownExperienceBottle.projectile().getBukkitEntity()); ++ final Projectile.Delayed thrownExperienceBottle = Projectile.spawnProjectileFromRotationDelayed(ThrownExperienceBottle::new, serverLevel, itemStack, player, -20.0F, 0.7F, 1.0F); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownExperienceBottle.projectile().getBukkitEntity()); + if (event.callEvent() && thrownExperienceBottle.attemptSpawn()) { + if (event.shouldConsume()) { -+ itemInHand.consume(1, player); ++ itemStack.consume(1, player); + } else { + player.containerMenu.forceHeldSlot(hand); + } @@ -46,7 +46,7 @@ } - player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- itemStack.consume(1, player); + // Paper - PlayerLaunchProjectileEvent - moved up return InteractionResult.SUCCESS; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/FireChargeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/FireChargeItem.java.patch index 0ea5aed2bbc2..49ed538b3d83 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/FireChargeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/FireChargeItem.java.patch @@ -2,30 +2,30 @@ +++ b/net/minecraft/world/item/FireChargeItem.java @@ -36,12 +_,28 @@ if (!CampfireBlock.canLight(blockState) && !CandleBlock.canLight(blockState) && !CandleCakeBlock.canLight(blockState)) { - clickedPos = clickedPos.relative(context.getClickedFace()); - if (BaseFireBlock.canBePlacedAt(level, clickedPos, context.getHorizontalDirection())) { + pos = pos.relative(context.getClickedFace()); + if (BaseFireBlock.canBePlacedAt(level, pos, context.getHorizontalDirection())) { + // CraftBukkit start - fire BlockIgniteEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, clickedPos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, pos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) { + if (!context.getPlayer().getAbilities().instabuild) { + context.getItemInHand().shrink(1); + } + return InteractionResult.PASS; + } + // CraftBukkit end - this.playSound(level, clickedPos); - level.setBlockAndUpdate(clickedPos, BaseFireBlock.getState(level, clickedPos)); - level.gameEvent(context.getPlayer(), GameEvent.BLOCK_PLACE, clickedPos); - flag = true; + this.playSound(level, pos); + level.setBlockAndUpdate(pos, BaseFireBlock.getState(level, pos)); + level.gameEvent(context.getPlayer(), GameEvent.BLOCK_PLACE, pos); + used = true; } } else { + // CraftBukkit start - fire BlockIgniteEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, clickedPos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, pos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) { + if (!context.getPlayer().getAbilities().instabuild) { + context.getItemInHand().shrink(1); + } + return InteractionResult.PASS; + } + // CraftBukkit end - this.playSound(level, clickedPos); - level.setBlockAndUpdate(clickedPos, blockState.setValue(BlockStateProperties.LIT, true)); - level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, clickedPos); + this.playSound(level, pos); + level.setBlockAndUpdate(pos, blockState.setValue(BlockStateProperties.LIT, true)); + level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch index 803d94ec2889..1aaf7897ede6 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch @@ -1,26 +1,26 @@ --- a/net/minecraft/world/item/FireworkRocketItem.java +++ b/net/minecraft/world/item/FireworkRocketItem.java @@ -36,7 +_,7 @@ - ItemStack itemInHand = context.getItemInHand(); + ItemStack itemStack = context.getItemInHand(); Vec3 clickLocation = context.getClickLocation(); - Direction clickedFace = context.getClickedFace(); + Direction direction = context.getClickedFace(); - Projectile.spawnProjectile( + final Projectile.Delayed fireworkRocketEntity = Projectile.spawnProjectileDelayed( // Paper - PlayerLaunchProjectileEvent new FireworkRocketEntity( level, context.getPlayer(), @@ -46,9 +_,14 @@ - itemInHand + itemStack ), serverLevel, -- itemInHand -+ itemInHand, f -> f.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID() // Paper - firework api - assign spawning entity uuid +- itemStack ++ itemStack, f -> f.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID() // Paper - firework api - assign spawning entity uuid ); -- itemInHand.shrink(1); +- itemStack.shrink(1); + // Paper start - PlayerLaunchProjectileEvent -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity()); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity()); + if (!event.callEvent() || !fireworkRocketEntity.attemptSpawn()) return InteractionResult.PASS; -+ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemInHand.shrink(1); ++ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemStack.shrink(1); + else context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); + // Paper end - PlayerLaunchProjectileEvent } @@ -28,20 +28,20 @@ return InteractionResult.SUCCESS; @@ -60,13 +_,24 @@ if (player.isFallFlying()) { - ItemStack itemInHand = player.getItemInHand(hand); + ItemStack itemStack = player.getItemInHand(hand); if (level instanceof ServerLevel serverLevel) { - if (player.dropAllLeashConnections(null)) { - level.playSound(null, player, SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F); + // Paper start - PlayerElytraBoostEvent -+ final Projectile.Delayed delayed = Projectile.spawnProjectileDelayed(new FireworkRocketEntity(level, itemInHand, player), serverLevel, itemInHand, f -> f.spawningEntity = player.getUUID()); // Paper - firework api - assign spawning entity uuid -+ com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)); ++ final Projectile.Delayed delayed = Projectile.spawnProjectileDelayed(new FireworkRocketEntity(level, itemStack, player), serverLevel, itemStack, f -> f.spawningEntity = player.getUUID()); // Paper - firework api - assign spawning entity uuid ++ com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)); + if (event.callEvent() && delayed.attemptSpawn()) { + player.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below + if (player.dropAllLeashConnections(null)) { + level.playSound(null, player, SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F); + } + if (event.shouldConsume() && !player.hasInfiniteMaterials()) { -+ itemInHand.shrink(1); // Moved up from below ++ itemStack.shrink(1); // Moved up from below + } else { + player.containerMenu.forceHeldSlot(hand); + } @@ -49,8 +49,8 @@ + player.containerMenu.forceHeldSlot(hand); } - -- Projectile.spawnProjectile(new FireworkRocketEntity(level, itemInHand, player), serverLevel, itemInHand); -- itemInHand.consume(1, player); +- Projectile.spawnProjectile(new FireworkRocketEntity(level, itemStack, player), serverLevel, itemStack); +- itemStack.consume(1, player); - player.awardStat(Stats.ITEM_USED.get(this)); + // Moved up consume and changed consume to shrink + // Paper end - PlayerElytraBoostEvent diff --git a/paper-server/patches/sources/net/minecraft/world/item/FishingRodItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/FishingRodItem.java.patch index 16bc842d8e84..c89981d9640b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/FishingRodItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/FishingRodItem.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/item/FishingRodItem.java +++ b/net/minecraft/world/item/FishingRodItem.java @@ -23,7 +_,7 @@ - ItemStack itemInHand = player.getItemInHand(hand); + ItemStack itemStack = player.getItemInHand(hand); if (player.fishing != null) { if (!level.isClientSide()) { -- int i = player.fishing.retrieve(itemInHand); -+ int i = player.fishing.retrieve(itemInHand, hand); // Paper - Add hand parameter to PlayerFishEvent - itemInHand.hurtAndBreak(i, player, hand.asEquipmentSlot()); +- int dmg = player.fishing.retrieve(itemStack); ++ int dmg = player.fishing.retrieve(itemStack, hand); // Paper - Add hand parameter to PlayerFishEvent + itemStack.hurtAndBreak(dmg, player, hand.asEquipmentSlot()); } @@ -39,20 +_,31 @@ ); - itemInHand.causeUseVibration(player, GameEvent.ITEM_INTERACT_FINISH); + itemStack.causeUseVibration(player, GameEvent.ITEM_INTERACT_FINISH); } else { - level.playSound( - null, @@ -25,11 +25,11 @@ - ); + // CraftBukkit - moved down if (level instanceof ServerLevel serverLevel) { - int i1 = (int)(EnchantmentHelper.getFishingTimeReduction(serverLevel, itemInHand, player) * 20.0F); - int fishingLuckBonus = EnchantmentHelper.getFishingLuckBonus(serverLevel, itemInHand, player); -- Projectile.spawnProjectile(new FishingHook(player, level, fishingLuckBonus, i1), serverLevel, itemInHand); + int lureSpeed = (int)(EnchantmentHelper.getFishingTimeReduction(serverLevel, itemStack, player) * 20.0F); + int luck = EnchantmentHelper.getFishingLuckBonus(serverLevel, itemStack, player); +- Projectile.spawnProjectile(new FishingHook(player, level, luck, lureSpeed), serverLevel, itemStack); + // CraftBukkit start -+ FishingHook fishingHook = new FishingHook(player, level, fishingLuckBonus, i1); ++ FishingHook fishingHook = new FishingHook(player, level, luck, lureSpeed); + org.bukkit.event.player.PlayerFishEvent playerFishEvent = new org.bukkit.event.player.PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), null, (org.bukkit.entity.FishHook) fishingHook.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), org.bukkit.event.player.PlayerFishEvent.State.FISHING); + level.getCraftServer().getPluginManager().callEvent(playerFishEvent); + @@ -47,7 +47,7 @@ + 0.5F, + 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F) + ); -+ Projectile.spawnProjectile(fishingHook, serverLevel, itemInHand); ++ Projectile.spawnProjectile(fishingHook, serverLevel, itemStack); + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/item/FlintAndSteelItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/FlintAndSteelItem.java.patch index f9aef7b267bf..7180cc2971ca 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/FlintAndSteelItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/FlintAndSteelItem.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/item/FlintAndSteelItem.java +++ b/net/minecraft/world/item/FlintAndSteelItem.java @@ -32,6 +_,12 @@ - if (!CampfireBlock.canLight(blockState) && !CandleBlock.canLight(blockState) && !CandleCakeBlock.canLight(blockState)) { - BlockPos blockPos = clickedPos.relative(context.getClickedFace()); - if (BaseFireBlock.canBePlacedAt(level, blockPos, context.getHorizontalDirection())) { + if (!CampfireBlock.canLight(state) && !CandleBlock.canLight(state) && !CandleCakeBlock.canLight(state)) { + BlockPos relativePos = pos.relative(context.getClickedFace()); + if (BaseFireBlock.canBePlacedAt(level, relativePos, context.getHorizontalDirection())) { + // CraftBukkit start - Store the clicked block -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, blockPos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, player).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, relativePos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, player).isCancelled()) { + context.getItemInHand().hurtAndBreak(1, player, context.getHand().asEquipmentSlot()); + return InteractionResult.PASS; + } + // CraftBukkit end - level.playSound(player, blockPos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F); - BlockState state = BaseFireBlock.getState(level, blockPos); - level.setBlock(blockPos, state, Block.UPDATE_ALL_IMMEDIATE); + level.playSound(player, relativePos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F); + BlockState fireState = BaseFireBlock.getState(level, relativePos); + level.setBlock(relativePos, fireState, Block.UPDATE_ALL_IMMEDIATE); @@ -47,6 +_,12 @@ return InteractionResult.FAIL; } } else { + // CraftBukkit start - Store the clicked block -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, clickedPos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, player).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, pos, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, player).isCancelled()) { + context.getItemInHand().hurtAndBreak(1, player, context.getHand().asEquipmentSlot()); + return InteractionResult.PASS; + } + // CraftBukkit end - level.playSound(player, clickedPos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F); - level.setBlock(clickedPos, blockState.setValue(BlockStateProperties.LIT, true), Block.UPDATE_ALL_IMMEDIATE); - level.gameEvent(player, GameEvent.BLOCK_CHANGE, clickedPos); + level.playSound(player, pos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F); + level.setBlock(pos, state.setValue(BlockStateProperties.LIT, true), Block.UPDATE_ALL_IMMEDIATE); + level.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch index 60601d933b5e..363bf1f36218 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/item/HangingEntityItem.java +++ b/net/minecraft/world/item/HangingEntityItem.java @@ -62,6 +_,20 @@ - EntityType.createDefaultStackConfig(level, itemInHand, player).accept(hangingEntity); - if (hangingEntity.survives()) { + EntityType.createDefaultStackConfig(level, itemInHand, player).accept(entity); + if (entity.survives()) { if (!level.isClientSide()) { + // CraftBukkit start - fire HangingPlaceEvent + org.bukkit.entity.Player bukkitPlayer = player == null ? null : (org.bukkit.entity.Player) player.getBukkitEntity(); @@ -10,7 +10,7 @@ + org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(clickedFace); + org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand()); + -+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) hangingEntity.getBukkitEntity(), bukkitPlayer, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemInHand)); ++ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) entity.getBukkitEntity(), bukkitPlayer, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemInHand)); + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { @@ -18,6 +18,6 @@ + return InteractionResult.FAIL; + } + // CraftBukkit end - hangingEntity.playPlacementSound(); - level.gameEvent(player, GameEvent.ENTITY_PLACE, hangingEntity.position()); - level.addFreshEntity(hangingEntity); + entity.playPlacementSound(); + level.gameEvent(player, GameEvent.ENTITY_PLACE, entity.position()); + level.addFreshEntity(entity); diff --git a/paper-server/patches/sources/net/minecraft/world/item/HoneycombItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/HoneycombItem.java.patch index 1710d50a1cac..4b222bd71be1 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/HoneycombItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/HoneycombItem.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/HoneycombItem.java +++ b/net/minecraft/world/item/HoneycombItem.java @@ -146,6 +_,14 @@ - return getWaxed(blockState).map(blockState1 -> { + return getWaxed(oldState).map(waxedState -> { Player player = context.getPlayer(); ItemStack itemInHand = context.getItemInHand(); + // Paper start - EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, blockState1)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, waxedState)) { + if (!player.isCreative()) { + player.containerMenu.forceHeldSlot(context.getHand()); + } @@ -13,5 +13,5 @@ + } + // Paper end if (player instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, clickedPos, itemInHand); + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, pos, itemInHand); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemCooldowns.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemCooldowns.java.patch index 902edf377e51..521dd59f86c5 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemCooldowns.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemCooldowns.java.patch @@ -3,14 +3,14 @@ @@ -56,6 +_,13 @@ } - public void addCooldown(Identifier group, int cooldown) { + public void addCooldown(final Identifier cooldownGroup, final int time) { + // Paper start - Item cooldown events -+ this.addCooldown(group, cooldown, true); ++ this.addCooldown(cooldownGroup, time, true); + } + -+ public void addCooldown(Identifier group, int cooldown, boolean callEvent) { ++ public void addCooldown(Identifier cooldownGroup, int time, boolean callEvent) { + // Event called in server override + // Paper end - Item cooldown events - this.cooldowns.put(group, new ItemCooldowns.CooldownInstance(this.tickCount, this.tickCount + cooldown)); - this.onCooldownStarted(group, cooldown); + this.cooldowns.put(cooldownGroup, new ItemCooldowns.CooldownInstance(this.tickCount, this.tickCount + time)); + this.onCooldownStarted(cooldownGroup, time); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch index c0db603550b7..1364e6e7bf25 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java -@@ -202,12 +_,20 @@ +@@ -187,12 +_,20 @@ @Override - public void encode(RegistryFriendlyByteBuf buffer, ItemStack value) { -- if (value.isEmpty()) { -+ if (value.isEmpty() || value.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem() - buffer.writeVarInt(0); + public void encode(final RegistryFriendlyByteBuf output, final ItemStack itemStack) { +- if (itemStack.isEmpty()) { ++ if (itemStack.isEmpty() || itemStack.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem() + output.writeVarInt(0); } else { -- buffer.writeVarInt(value.getCount()); -+ buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), value, value.getCount())); // Paper - potentially sanitize count - Item.STREAM_CODEC.encode(buffer, value.getItemHolder()); +- output.writeVarInt(itemStack.getCount()); ++ output.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), itemStack, itemStack.getCount())); // Paper - potentially sanitize count + Item.STREAM_CODEC.encode(output, itemStack.typeHolder()); + // Paper start - adventure; conditionally render translatable components + boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get(); -+ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(value))) { // pass the itemstack as context to the obfuscation session ++ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(itemStack))) { // pass the itemstack as context to the obfuscation session + net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true); - codec.encode(buffer, value.components.asPatch()); + patchCodec.encode(output, itemStack.components.asPatch()); + } finally { + net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev); + } @@ -23,26 +23,26 @@ } } }; -@@ -371,10 +_,166 @@ +@@ -368,10 +_,166 @@ return InteractionResult.PASS; } else { - Item item = this.getItem(); -- InteractionResult interactionResult = item.useOn(context); + Item usedItem = this.getItem(); +- InteractionResult result = usedItem.useOn(context); + // CraftBukkit start - handle all block place event logic here + DataComponentPatch previousPatch = this.components.asPatch(); + int oldCount = this.getCount(); + ServerLevel serverLevel = (ServerLevel) context.getLevel(); + -+ if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement ++ if (!(usedItem instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement + serverLevel.captureBlockStates = true; + // special case bonemeal -+ if (item == Items.BONE_MEAL) { ++ if (usedItem == Items.BONE_MEAL) { + serverLevel.captureTreeGeneration = true; + } + } -+ InteractionResult interactionResult; ++ InteractionResult result; + try { -+ interactionResult = item.useOn(context); ++ result = usedItem.useOn(context); + } finally { + serverLevel.captureBlockStates = false; + } @@ -50,9 +50,9 @@ + int newCount = this.getCount(); + this.setCount(oldCount); + this.restorePatch(previousPatch); -+ if (interactionResult.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) { ++ if (result.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) { + serverLevel.captureTreeGeneration = false; -+ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(clickedPos, serverLevel); ++ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, serverLevel); + org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; + net.minecraft.world.level.block.SaplingBlock.treeType = null; + List blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values()); @@ -64,7 +64,7 @@ + org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent); + } + -+ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, clickedPos), (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); ++ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, pos), (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); + fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled()); + org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent); + @@ -77,29 +77,29 @@ + for (org.bukkit.craftbukkit.block.CraftBlockState snapshot : blocks) { + // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest + snapshot.place(snapshot.getFlags()); -+ serverLevel.checkCapturedTreeStateForObserverNotify(clickedPos, snapshot); // Paper - notify observers even if grow failed ++ serverLevel.checkCapturedTreeStateForObserverNotify(pos, snapshot); // Paper - notify observers even if grow failed + } -+ player.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat ++ player.awardStat(Stats.ITEM_USED.get(usedItem)); // SPIGOT-7236 - award stat + } + + SignItem.openSign = null; // SPIGOT-6758 - Reset on early return -+ return interactionResult; ++ return result; + } + serverLevel.captureTreeGeneration = false; - if (player != null && interactionResult instanceof InteractionResult.Success success && success.wasItemInteraction()) { -- player.awardStat(Stats.ITEM_USED.get(item)); + if (player != null && result instanceof InteractionResult.Success success && success.wasItemInteraction()) { +- player.awardStat(Stats.ITEM_USED.get(usedItem)); + InteractionHand hand = context.getHand(); + org.bukkit.event.block.BlockPlaceEvent placeEvent = null; + List blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values()); + serverLevel.capturedBlockStates.clear(); + if (blocks.size() > 1) { -+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(serverLevel, player, hand, blocks, clickedPos); -+ } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement -+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(serverLevel, player, hand, blocks.getFirst(), clickedPos); ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(serverLevel, player, hand, blocks, pos); ++ } else if (blocks.size() == 1 && usedItem != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(serverLevel, player, hand, blocks.getFirst(), pos); + } + + if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { -+ interactionResult = InteractionResult.FAIL; // cancel placement ++ result = InteractionResult.FAIL; // cancel placement + // PAIL: Remove this when MC-99075 fixed + player.containerMenu.forceHeldSlot(hand); + serverLevel.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot @@ -134,9 +134,9 @@ + } + + if (this.item == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled -+ BlockPos bp = clickedPos; -+ if (!serverLevel.getBlockState(clickedPos).canBeReplaced()) { -+ if (!serverLevel.getBlockState(clickedPos).isSolid()) { ++ BlockPos bp = pos; ++ if (!serverLevel.getBlockState(pos).canBeReplaced()) { ++ if (!serverLevel.getBlockState(pos).isSolid()) { + bp = null; + } else { + bp = bp.relative(context.getClickedFace()); @@ -165,12 +165,12 @@ + + // SPIGOT-7315: Moved from BedBlock#setPlacedBy + if (placeEvent != null && this.item instanceof BedItem) { -+ BlockPos pos = ((org.bukkit.craftbukkit.block.CraftBlock) placeEvent.getBlock()).getPosition(); -+ net.minecraft.world.level.block.state.BlockState state = serverLevel.getBlockState(pos); ++ BlockPos bedPos = ((org.bukkit.craftbukkit.block.CraftBlock) placeEvent.getBlock()).getPosition(); ++ net.minecraft.world.level.block.state.BlockState state = serverLevel.getBlockState(bedPos); + + if (state.getBlock() instanceof net.minecraft.world.level.block.BedBlock) { -+ serverLevel.updateNeighborsAt(pos, net.minecraft.world.level.block.Blocks.AIR); -+ state.updateNeighbourShapes(serverLevel, pos, net.minecraft.world.level.block.Block.UPDATE_ALL); ++ serverLevel.updateNeighborsAt(bedPos, net.minecraft.world.level.block.Blocks.AIR); ++ state.updateNeighbourShapes(serverLevel, bedPos, net.minecraft.world.level.block.Block.UPDATE_ALL); + } + } + @@ -180,64 +180,64 @@ + net.minecraft.world.level.block.state.BlockState state = serverLevel.getBlockState(success.paperSuccessContext().placedBlockPosition()); + net.minecraft.world.level.block.SoundType soundType = state.getSoundType(); + // Paper end - Fix spigot sound playing for BlockItem ItemStacks -+ serverLevel.playSound(player, clickedPos, soundType.getPlaceSound(), net.minecraft.sounds.SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); ++ serverLevel.playSound(player, pos, soundType.getPlaceSound(), net.minecraft.sounds.SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } + -+ player.awardStat(Stats.ITEM_USED.get(item)); ++ player.awardStat(Stats.ITEM_USED.get(usedItem)); + } } + serverLevel.capturedTileEntities.clear(); + serverLevel.capturedBlockStates.clear(); + // CraftBukkit end - return interactionResult; + return result; } -@@ -455,31 +_,67 @@ +@@ -448,31 +_,67 @@ return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1; } -- public void hurtAndBreak(int damage, ServerLevel level, @Nullable ServerPlayer player, Consumer onBreak) { -- int i = this.processDurabilityChange(damage, level, player); -- if (i != 0) { -+ public void hurtAndBreak(int damage, ServerLevel level, @Nullable LivingEntity player, Consumer onBreak) { // Paper - Add EntityDamageItemEvent +- public void hurtAndBreak(final int amount, final ServerLevel level, final @Nullable ServerPlayer player, final Consumer onBreak) { +- int newAmount = this.processDurabilityChange(amount, level, player); +- if (newAmount != 0) { ++ public void hurtAndBreak(final int amount, final ServerLevel level, final @Nullable LivingEntity player, final Consumer onBreak) { // Paper - Add EntityDamageItemEvent + // Paper start - add force boolean overload -+ this.hurtAndBreak(damage, level, player, onBreak, false); ++ this.hurtAndBreak(amount, level, player, onBreak, false); + } + -+ public void hurtAndBreak(int damage, ServerLevel level, @Nullable LivingEntity player, Consumer onBreak, boolean force) { // Paper - Add EntityDamageItemEvent ++ public void hurtAndBreak(final int amount, final ServerLevel level, final @Nullable LivingEntity player, final Consumer onBreak, final boolean force) { // Paper - Add EntityDamageItemEvent + // Paper end -+ final int originalDamage = damage; // Paper - Expand PlayerItemDamageEvent -+ int i = this.processDurabilityChange(damage, level, player, force); // Paper ++ final int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent ++ int newAmount = this.processDurabilityChange(amount, level, player, force); // Paper + // CraftBukkit start -+ if (i > 0 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent - limit to positive damage and run for player -+ org.bukkit.event.player.PlayerItemDamageEvent event = new org.bukkit.event.player.PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), i, originalDamage); // Paper - Add EntityDamageItemEvent ++ if (newAmount > 0 && player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent - limit to positive damage and run for player ++ org.bukkit.event.player.PlayerItemDamageEvent event = new org.bukkit.event.player.PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), newAmount, originalDamage); // Paper - Add EntityDamageItemEvent + event.getPlayer().getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + -+ i = event.getDamage(); ++ newAmount = event.getDamage(); + // Paper start - Add EntityDamageItemEvent -+ } else if (i > 0 && player != null) { -+ io.papermc.paper.event.entity.EntityDamageItemEvent event = new io.papermc.paper.event.entity.EntityDamageItemEvent(player.getBukkitLivingEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), i); ++ } else if (newAmount > 0 && player != null) { ++ io.papermc.paper.event.entity.EntityDamageItemEvent event = new io.papermc.paper.event.entity.EntityDamageItemEvent(player.getBukkitLivingEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), newAmount); + if (!event.callEvent()) { + return; + } -+ i = event.getDamage(); ++ newAmount = event.getDamage(); + // Paper end - Add EntityDamageItemEvent + } + // CraftBukkit end -+ if (i != 0) { // Paper - Add EntityDamageItemEvent - diff on change for above event ifs. - this.applyDamage(this.getDamageValue() + i, player, onBreak); ++ if (newAmount != 0) { // Paper - Add EntityDamageItemEvent - diff on change for above event ifs. + this.applyDamage(this.getDamageValue() + newAmount, player, onBreak); } } -- private int processDurabilityChange(int damage, ServerLevel level, @Nullable ServerPlayer player) { -+ private int processDurabilityChange(int damage, ServerLevel level, @Nullable LivingEntity player) { // Paper - Add EntityDamageItemEvent +- private int processDurabilityChange(final int amount, final ServerLevel level, final @Nullable ServerPlayer player) { ++ private int processDurabilityChange(final int amount, final ServerLevel level, final @Nullable LivingEntity player) { // Paper - Add EntityDamageItemEvent + // Paper start - itemstack damage api -+ return processDurabilityChange(damage, level, player, false); ++ return this.processDurabilityChange(amount, level, player, false); + } -+ private int processDurabilityChange(int damage, ServerLevel level, @Nullable LivingEntity player, boolean force) { ++ private int processDurabilityChange(final int amount, final ServerLevel level, final @Nullable LivingEntity player, final boolean force) { + // Paper end - itemstack damage api if (!this.isDamageableItem()) { return 0; @@ -245,19 +245,19 @@ + } else if (player instanceof ServerPlayer && player.hasInfiniteMaterials() && !force) { // Paper - Add EntityDamageItemEvent return 0; } else { - return damage > 0 ? EnchantmentHelper.processDurabilityChange(level, this, damage) : damage; + return amount > 0 ? EnchantmentHelper.processDurabilityChange(level, this, amount) : amount; } } -- private void applyDamage(int damage, @Nullable ServerPlayer player, Consumer onBreak) { +- private void applyDamage(final int newDamage, final @Nullable ServerPlayer player, final Consumer onBreak) { - if (player != null) { -- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, damage); -+ private void applyDamage(int damage, @Nullable LivingEntity player, Consumer onBreak) { // Paper - Add EntityDamageItemEvent +- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, newDamage); ++ private void applyDamage(final int newDamage, final @Nullable LivingEntity player, final Consumer onBreak) { // Paper - Add EntityDamageItemEvent + if (player instanceof final ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent -+ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, this, damage); // Paper - Add EntityDamageItemEvent ++ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, this, newDamage); // Paper - Add EntityDamageItemEvent } - this.setDamageValue(damage); + this.setDamageValue(newDamage); if (this.isBroken()) { Item item = this.getItem(); + // CraftBukkit start - Check for item breaking @@ -268,20 +268,20 @@ this.shrink(1); onBreak.accept(item); } -@@ -492,7 +_,26 @@ +@@ -485,7 +_,26 @@ return; } -- int min = Math.min(this.getDamageValue() + i, this.getMaxDamage() - 1); -+ int min = Math.min(this.getDamageValue() + i, this.getMaxDamage() - 1); // Paper - Expand PlayerItemDamageEvent - diff on change as min computation is copied post event. +- int newDamage = Math.min(this.getDamageValue() + newAmount, this.getMaxDamage() - 1); ++ int newDamage = Math.min(this.getDamageValue() + newAmount, this.getMaxDamage() - 1); // Paper - Expand PlayerItemDamageEvent - diff on change as min computation is copied post event. + + // Paper start - Expand PlayerItemDamageEvent -+ if (min - this.getDamageValue() > 0) { ++ if (newDamage - this.getDamageValue() > 0) { + org.bukkit.event.player.PlayerItemDamageEvent event = new org.bukkit.event.player.PlayerItemDamageEvent( + serverPlayer.getBukkitEntity(), + org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this), -+ min - this.getDamageValue(), -+ damage ++ newDamage - this.getDamageValue(), ++ amount + ); + if (!event.callEvent() || event.getDamage() == 0) { + return; @@ -289,30 +289,30 @@ + + // Prevent breaking the item in this code path as callers may expect the item to survive + // (given the method name) -+ min = Math.min(this.getDamageValue() + event.getDamage(), this.getMaxDamage() - 1); ++ newDamage = Math.min(this.getDamageValue() + event.getDamage(), this.getMaxDamage() - 1); + } + // Paper end - Expand PlayerItemDamageEvent + - this.applyDamage(min, serverPlayer, item -> {}); + this.applyDamage(newDamage, serverPlayer, i -> {}); } } -@@ -502,9 +_,14 @@ +@@ -495,9 +_,14 @@ } - public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot) { + public void hurtAndBreak(final int amount, final LivingEntity owner, final EquipmentSlot slot) { + // Paper start - add param to skip infinite mats check -+ this.hurtAndBreak(amount, entity, slot, false); ++ this.hurtAndBreak(amount, owner, slot, false); + } -+ public void hurtAndBreak(int amount, LivingEntity entity, EquipmentSlot slot, boolean force) { ++ public void hurtAndBreak(final int amount, final LivingEntity owner, final EquipmentSlot slot, final boolean force) { + // Paper end - add param to skip infinite mats check - if (entity.level() instanceof ServerLevel serverLevel) { + if (owner.level() instanceof ServerLevel serverLevel) { this.hurtAndBreak( -- amount, serverLevel, entity instanceof ServerPlayer serverPlayer ? serverPlayer : null, item -> entity.onEquippedItemBroken(item, slot) -+ amount, serverLevel, entity, item -> {if (slot != null) entity.onEquippedItemBroken(item, slot); }, force // Paper - Add EntityDamageItemEvent & itemstack damage API - do not process entity related callbacks when damaging from API +- amount, serverLevel, owner instanceof ServerPlayer player ? player : null, brokenItem -> owner.onEquippedItemBroken(brokenItem, slot) ++ amount, serverLevel, owner, brokenItem -> {if (slot != null) owner.onEquippedItemBroken(brokenItem, slot); }, force // Paper - Add EntityDamageItemEvent & itemstack damage API - do not process entity related callbacks when damaging from API ); } } -@@ -753,6 +_,12 @@ +@@ -748,6 +_,12 @@ return this.getItem().useOnRelease(this); } @@ -322,10 +322,10 @@ + } + // CraftBukkit end + - public @Nullable T set(DataComponentType component, @Nullable T value) { - return this.components.set(component, value); + public @Nullable T set(final DataComponentType type, final @Nullable T value) { + return this.components.set(type, value); } -@@ -796,6 +_,28 @@ +@@ -791,6 +_,28 @@ this.components.setAll(components); } @@ -354,15 +354,15 @@ public Component getHoverName() { Component customName = this.getCustomName(); return customName != null ? customName : this.getItemName(); -@@ -1026,6 +_,19 @@ - EnchantmentHelper.forEachModifier(this, slot, action); +@@ -1006,6 +_,19 @@ + EnchantmentHelper.forEachModifier(this, slot, consumer); } + // CraftBukkit start + @Deprecated + public void setItem(Item item) { + this.bukkitStack = null; // Paper -+ this.item = item; ++ this.item = item.builtInRegistryHolder(); + // Paper start - change base component prototype + final DataComponentPatch patch = this.getComponentsPatch(); + this.components = new PatchedDataComponentMap(this.item.components()); @@ -372,14 +372,14 @@ + // CraftBukkit end + public Component getDisplayName() { - MutableComponent mutableComponent = Component.empty().append(this.getHoverName()); + MutableComponent hoverName = Component.empty().append(this.getHoverName()); if (this.has(DataComponents.CUSTOM_NAME)) { -@@ -1085,7 +_,7 @@ +@@ -1070,7 +_,7 @@ } - public void consume(int amount, @Nullable LivingEntity entity) { -- if (entity == null || !entity.hasInfiniteMaterials()) { -+ if ((entity == null || !entity.hasInfiniteMaterials()) && this != ItemStack.EMPTY) { // CraftBukkit + public void consume(final int amount, final @Nullable LivingEntity owner) { +- if (owner == null || !owner.hasInfiniteMaterials()) { ++ if ((owner == null || !owner.hasInfiniteMaterials()) && this != ItemStack.EMPTY) { // CraftBukkit this.shrink(amount); } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemUtils.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemUtils.java.patch index 72de90ab1c6c..3a9b7477d9e9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemUtils.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemUtils.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/item/ItemUtils.java +++ b/net/minecraft/world/item/ItemUtils.java -@@ -41,7 +_,15 @@ - public static void onContainerDestroyed(ItemEntity container, Iterable contents) { +@@ -44,7 +_,15 @@ + public static void onContainerDestroyed(final ItemEntity container, final Stream contents) { Level level = container.level(); if (!level.isClientSide()) { -- contents.forEach(itemStack -> level.addFreshEntity(new ItemEntity(level, container.getX(), container.getY(), container.getZ(), itemStack))); +- contents.forEach(stack -> level.addFreshEntity(new ItemEntity(level, container.getX(), container.getY(), container.getZ(), stack))); + // Paper start - call EntityDropItemEvent -+ contents.forEach(itemStack -> { -+ ItemEntity droppedItem = new ItemEntity(level, container.getX(), container.getY(), container.getZ(), itemStack); ++ contents.forEach(stack -> { ++ ItemEntity droppedItem = new ItemEntity(level, container.getX(), container.getY(), container.getZ(), stack); + org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(container.getBukkitEntity(), (org.bukkit.entity.Item) droppedItem.getBukkitEntity()); + if (event.callEvent()) { + level.addFreshEntity(droppedItem); diff --git a/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch index 5d84bec664fe..7f93debcac9a 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch @@ -1,58 +1,47 @@ --- a/net/minecraft/world/item/LeadItem.java +++ b/net/minecraft/world/item/LeadItem.java -@@ -26,25 +_,38 @@ - if (blockState.is(BlockTags.FENCES)) { +@@ -27,24 +_,36 @@ + if (state.is(BlockTags.FENCES)) { Player player = context.getPlayer(); if (!level.isClientSide() && player != null) { -- return bindPlayerMobs(player, level, clickedPos); -+ return bindPlayerMobs(player, level, clickedPos, context.getHand()); // CraftBukkit - Pass hand +- return bindPlayerMobs(player, level, pos); ++ return bindPlayerMobs(player, level, pos, context.getHand()); // CraftBukkit - Pass hand } } return InteractionResult.PASS; } -- public static InteractionResult bindPlayerMobs(Player player, Level level, BlockPos pos) { -+ public static InteractionResult bindPlayerMobs(Player player, Level level, BlockPos pos, net.minecraft.world.InteractionHand interactionHand) { // CraftBukkit - Add InteractionHand - LeashFenceKnotEntity leashFenceKnotEntity = null; - List list = Leashable.leashableInArea(level, Vec3.atCenterOf(pos), leashable1 -> leashable1.getLeashHolder() == player); - boolean flag = false; - - for (Leashable leashable : list) { - if (leashFenceKnotEntity == null) { -- leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos); -+ // CraftBukkit start - fire HangingPlaceEvent -+ org.apache.commons.lang3.mutable.MutableBoolean created = new org.apache.commons.lang3.mutable.MutableBoolean(false); -+ leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos, created); -+ if (created.booleanValue()) { -+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(interactionHand); -+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) leashFenceKnotEntity.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, hand); -+ level.getCraftServer().getPluginManager().callEvent(event); +- public static InteractionResult bindPlayerMobs(final Player player, final Level level, final BlockPos pos) { ++ public static InteractionResult bindPlayerMobs(final Player player, final Level level, final BlockPos pos, final net.minecraft.world.InteractionHand hand) { // CraftBukkit - Add InteractionHand + List entitiesToLeash = Leashable.leashableInArea(level, Vec3.atCenterOf(pos), l -> l.getLeashHolder() == player); + if (entitiesToLeash.isEmpty()) { + return InteractionResult.PASS; + } else { + Optional existingKnot = LeashFenceKnotEntity.getKnot(level, pos); + LeashFenceKnotEntity activeKnot = existingKnot.orElseGet(() -> LeashFenceKnotEntity.createKnot(level, pos)); ++ // CraftBukkit start - fire HangingPlaceEvent ++ if (existingKnot.isEmpty()) { ++ org.bukkit.inventory.EquipmentSlot handSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); ++ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) activeKnot.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, handSlot); ++ level.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ leashFenceKnotEntity.discard(null); -+ return InteractionResult.PASS; -+ } ++ if (event.isCancelled()) { ++ activeKnot.discard(); ++ return InteractionResult.PASS; + } -+ // CraftBukkit end - leashFenceKnotEntity.playPlacementSound(); - } - -- if (leashable.canHaveALeashAttachedTo(leashFenceKnotEntity)) { -+ if (leashable.canHaveALeashAttachedTo(leashFenceKnotEntity) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, leashFenceKnotEntity, player, interactionHand)) { // Paper - leash event - leashable.setLeashedTo(leashFenceKnotEntity, true); - flag = true; - } -@@ -54,7 +_,18 @@ - level.gameEvent(GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of(player)); - return InteractionResult.SUCCESS_SERVER; - } else { -+ // CraftBukkit start - remove leash if we do not leash any entity because of the cancelled event -+ if (leashFenceKnotEntity != null) { -+ leashFenceKnotEntity.discard(null); + } + // CraftBukkit end - return InteractionResult.PASS; + boolean anyLeashed = false; + + for (Leashable leashable : entitiesToLeash) { +- if (leashable.canHaveALeashAttachedTo(activeKnot)) { ++ if (leashable.canHaveALeashAttachedTo(activeKnot) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, activeKnot, player, hand)) { // Paper - leash event + leashable.setLeashedTo(activeKnot, true); + anyLeashed = true; + } +@@ -63,4 +_,10 @@ + } } } + diff --git a/paper-server/patches/sources/net/minecraft/world/item/LingeringPotionItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/LingeringPotionItem.java.patch index f4ab3c1e4d0f..7d1956feb87a 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/LingeringPotionItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/LingeringPotionItem.java.patch @@ -3,7 +3,7 @@ @@ -19,6 +_,10 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + // Paper start - PlayerLaunchProjectileEvent + final InteractionResult wrapper = super.use(level, player, hand); + if (wrapper instanceof InteractionResult.Fail) return wrapper; diff --git a/paper-server/patches/sources/net/minecraft/world/item/MaceItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/MaceItem.java.patch index 5d1dddfbae69..c770adf7c823 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/MaceItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/MaceItem.java.patch @@ -3,24 +3,24 @@ @@ -54,7 +_,13 @@ @Override - public void hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + public void hurtEnemy(final ItemStack itemStack, final LivingEntity mob, final LivingEntity attacker) { - if (canSmashAttack(attacker)) { + // Paper start - Add EntityAttemptSmashAttackEvent + final boolean canSmashAttack = canSmashAttack(attacker); -+ io.papermc.paper.event.entity.EntityAttemptSmashAttackEvent event = new io.papermc.paper.event.entity.EntityAttemptSmashAttackEvent(attacker.getBukkitLivingEntity(), target.getBukkitLivingEntity(), stack.asBukkitCopy(), canSmashAttack); ++ io.papermc.paper.event.entity.EntityAttemptSmashAttackEvent event = new io.papermc.paper.event.entity.EntityAttemptSmashAttackEvent(attacker.getBukkitLivingEntity(), mob.getBukkitLivingEntity(), itemStack.asBukkitCopy(), canSmashAttack); + event.callEvent(); + final org.bukkit.event.Event.Result result = event.getResult(); + if (result == org.bukkit.event.Event.Result.ALLOW || (canSmashAttack && result == org.bukkit.event.Event.Result.DEFAULT)) { + // Paper end - Add EntityAttemptSmashAttackEvent - ServerLevel serverLevel = (ServerLevel)attacker.level(); + ServerLevel level = (ServerLevel)attacker.level(); attacker.setDeltaMovement(attacker.getDeltaMovement().with(Direction.Axis.Y, 0.01F)); - if (attacker instanceof ServerPlayer serverPlayer) { -@@ -129,7 +_,7 @@ - double knockbackPower = getKnockbackPower(attacker, livingEntity, vec3); - Vec3 vec31 = vec3.normalize().scale(knockbackPower); + attacker.setIgnoreFallDamageFromCurrentImpulse(true, this.calculateImpactPosition(attacker)); +@@ -124,7 +_,7 @@ + double knockbackPower = getKnockbackPower(attacker, nearby, direction); + Vec3 knockbackVector = direction.normalize().scale(knockbackPower); if (knockbackPower > 0.0) { -- livingEntity.push(vec31.x, 0.7F, vec31.z); -+ livingEntity.push(vec31.x, 0.7F, vec31.z, attacker); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - if (livingEntity instanceof ServerPlayer serverPlayer) { - serverPlayer.connection.send(new ClientboundSetEntityMotionPacket(serverPlayer)); +- nearby.push(knockbackVector.x, 0.7F, knockbackVector.z); ++ nearby.push(knockbackVector.x, 0.7F, knockbackVector.z, attacker); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + if (nearby instanceof ServerPlayer otherPlayer) { + otherPlayer.connection.send(new ClientboundSetEntityMotionPacket(otherPlayer)); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/MapItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/MapItem.java.patch index 07a53be2f8aa..da33116353e1 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/MapItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/MapItem.java.patch @@ -1,22 +1,24 @@ --- a/net/minecraft/world/item/MapItem.java +++ b/net/minecraft/world/item/MapItem.java -@@ -95,8 +_,8 @@ - int i9 = (i1 / i + i6 - 64) * i; - int i10 = (i2 / i + i7 - 64) * i; - Multiset multiset = LinkedHashMultiset.create(); -- LevelChunk chunk = level.getChunk(SectionPos.blockToSectionCoord(i9), SectionPos.blockToSectionCoord(i10)); +@@ -103,10 +_,10 @@ + int averagingAreaMinX = (centerX / scale + imgX - 64) * scale; + int averagingAreaMinZ = (centerZ / scale + imgY - 64) * scale; + Multiset colorCount = LinkedHashMultiset.create(); +- LevelChunk chunk = level.getChunk( ++ LevelChunk chunk = level.getChunkIfLoaded( // Paper - Maps shouldn't load chunks + SectionPos.blockToSectionCoord(averagingAreaMinX), SectionPos.blockToSectionCoord(averagingAreaMinZ) + ); - if (!chunk.isEmpty()) { -+ LevelChunk chunk = level.getChunkIfLoaded(SectionPos.blockToSectionCoord(i9), SectionPos.blockToSectionCoord(i10)); // Paper - Maps shouldn't load chunks + if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks - int i11 = 0; - double d1 = 0.0; + int waterDepth = 0; + double averageAreaHeight = 0.0; if (level.dimensionType().hasCeiling()) { -@@ -203,7 +_,7 @@ +@@ -213,7 +_,7 @@ - for (int i5 = 0; i5 < 128; i5++) { - for (int i6 = 0; i6 < 128; i6++) { -- Holder biome = level.getBiome(mutableBlockPos.set((i3 + i6) * i, 0, (i4 + i5) * i)); -+ Holder biome = level.getUncachedNoiseBiome(net.minecraft.core.QuartPos.fromBlock((i3 + i6) * i), net.minecraft.core.QuartPos.fromBlock(0), net.minecraft.core.QuartPos.fromBlock((i4 + i5) * i)); // Paper - Perf: Use seed based lookup for treasure maps - flags[i5 * 128 + i6] = biome.is(BiomeTags.WATER_ON_MAP_OUTLINES); + for (int row = 0; row < 128; row++) { + for (int column = 0; column < 128; column++) { +- Holder biome = level.getBiome(pos.set((unscaledStartX + column) * scale, 0, (unscaledStartZ + row) * scale)); ++ Holder biome = level.getUncachedNoiseBiome(net.minecraft.core.QuartPos.fromBlock((unscaledStartX + column) * scale), net.minecraft.core.QuartPos.fromBlock(0), net.minecraft.core.QuartPos.fromBlock((unscaledStartZ + row) * scale)); // Paper - Perf: Use seed based lookup for treasure maps + isBiomeWatery[row * 128 + column] = biome.is(BiomeTags.WATER_ON_MAP_OUTLINES); } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch index 20602408ae1a..70ccca3b2790 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch @@ -4,14 +4,14 @@ } if (level instanceof ServerLevel serverLevel) { -- serverLevel.addFreshEntity(abstractMinecart); +- serverLevel.addFreshEntity(cart); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, abstractMinecart).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, cart).isCancelled()) { + if (context.getPlayer() != null) context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); // Paper - Fix inventory desync + return InteractionResult.FAIL; + } + // CraftBukkit end -+ if (!serverLevel.addFreshEntity(abstractMinecart)) return InteractionResult.PASS; // CraftBukkit - serverLevel.gameEvent( - GameEvent.ENTITY_PLACE, clickedPos, GameEvent.Context.of(context.getPlayer(), serverLevel.getBlockState(clickedPos.below())) - ); ++ if (!serverLevel.addFreshEntity(cart)) return InteractionResult.PASS; // CraftBukkit + serverLevel.gameEvent(GameEvent.ENTITY_PLACE, pos, GameEvent.Context.of(context.getPlayer(), serverLevel.getBlockState(pos.below()))); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/item/NameTagItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/NameTagItem.java.patch index bdaa9c8bff13..5ec1f516e675 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/NameTagItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/NameTagItem.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/item/NameTagItem.java +++ b/net/minecraft/world/item/NameTagItem.java @@ -18,8 +_,14 @@ - Component component = stack.get(DataComponents.CUSTOM_NAME); - if (component != null && target.getType().canSerialize()) { + Component customName = itemStack.get(DataComponents.CUSTOM_NAME); + if (customName != null && target.getType().canSerialize()) { if (!player.level().isClientSide() && target.isAlive()) { -- target.setCustomName(component); +- target.setCustomName(customName); - if (target instanceof Mob mob) { + // Paper start - Add PlayerNameEntityEvent -+ io.papermc.paper.event.player.PlayerNameEntityEvent event = new io.papermc.paper.event.player.PlayerNameEntityEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), target.getBukkitLivingEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(stack.getHoverName()), true); ++ io.papermc.paper.event.player.PlayerNameEntityEvent event = new io.papermc.paper.event.player.PlayerNameEntityEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), target.getBukkitLivingEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(customName), true); + if (!event.callEvent()) return InteractionResult.PASS; + + LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); diff --git a/paper-server/patches/sources/net/minecraft/world/item/PotionItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/PotionItem.java.patch index 89035150a173..016c49bf6b47 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/PotionItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/PotionItem.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/item/PotionItem.java +++ b/net/minecraft/world/item/PotionItem.java @@ -40,6 +_,16 @@ - PotionContents potionContents = itemInHand.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); - BlockState blockState = level.getBlockState(clickedPos); + PotionContents potionContents = itemStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + BlockState blockState = level.getBlockState(pos); if (context.getClickedFace() != Direction.DOWN && blockState.is(BlockTags.CONVERTABLE_TO_MUD) && potionContents.is(Potions.WATER)) { + // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, Blocks.MUD.defaultBlockState())) { -+ if (itemInHand.getCount() > 1 || player.hasInfiniteMaterials()) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, Blocks.MUD.defaultBlockState())) { ++ if (itemStack.getCount() > 1 || player.hasInfiniteMaterials()) { + player.containerMenu.sendAllDataToRemote(); + } else { + player.containerMenu.forceHeldSlot(context.getHand()); @@ -14,6 +14,6 @@ + return InteractionResult.PASS; + } + // Paper end - level.playSound(null, clickedPos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F); - player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE))); + level.playSound(null, pos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F); + player.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemStack, player, new ItemStack(Items.GLASS_BOTTLE))); if (!level.isClientSide()) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch index c3731d881146..c87d9272fa57 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch @@ -1,64 +1,65 @@ --- a/net/minecraft/world/item/ProjectileWeaponItem.java +++ b/net/minecraft/world/item/ProjectileWeaponItem.java @@ -50,6 +_,7 @@ - float inaccuracy, - boolean isCrit, - @Nullable LivingEntity target -+ ,float drawStrength // Paper - Pass draw strength + final float uncertainty, + final boolean isCrit, + final @Nullable LivingEntity targetOverride ++ , final float drawStrength // Paper - Pass draw strength ) { - float f = EnchantmentHelper.processProjectileSpread(level, weapon, shooter, 0.0F); - float f1 = projectileItems.size() == 1 ? 0.0F : 2.0F * f / (projectileItems.size() - 1); + float maxAngle = EnchantmentHelper.processProjectileSpread(level, weapon, shooter, 0.0F); + float angleStep = projectiles.size() == 1 ? 0.0F : 2.0F * maxAngle / (projectiles.size() - 1); @@ -62,12 +_,26 @@ - float f4 = f2 + f3 * ((i + 1) / 2) * f1; - f3 = -f3; - int i1 = i; + float angle = angleOffset + direction * ((i + 1) / 2) * angleStep; + direction = -direction; + int index = i; - Projectile.spawnProjectile( -- this.createProjectile(level, shooter, weapon, itemStack, isCrit), +- this.createProjectile(level, shooter, weapon, projectile, isCrit), - level, -- itemStack, -- projectile -> this.shootProjectile(shooter, projectile, i1, velocity, inaccuracy, f4, target) +- projectile, +- projectileEntity -> this.shootProjectile(shooter, projectileEntity, index, power, uncertainty, angle, targetOverride) - ); + // CraftBukkit start -+ Projectile projectile = this.createProjectile(level, shooter, weapon, itemStack, isCrit); -+ this.shootProjectile(shooter, projectile, i1, velocity, inaccuracy, f4, target); ++ Projectile projectileEntity = this.createProjectile(level, shooter, weapon, projectile, isCrit); ++ this.shootProjectile(shooter, projectileEntity, index, power, uncertainty, angle, targetOverride); + -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, itemStack, projectile, hand, drawStrength, true); ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, weapon, projectile, projectileEntity, hand, drawStrength, true); + if (event.isCancelled()) { + event.getProjectile().remove(); + return; + } + -+ if (event.getProjectile() == projectile.getBukkitEntity()) { ++ if (event.getProjectile() == projectileEntity.getBukkitEntity()) { + if (Projectile.spawnProjectile( -+ projectile, ++ projectileEntity, + level, -+ itemStack ++ projectile + ).isRemoved()) { + return; + } + } + // CraftBukkit end - weapon.hurtAndBreak(this.getDurabilityUse(itemStack), shooter, hand.asEquipmentSlot()); + weapon.hurtAndBreak(this.getDurabilityUse(projectile), shooter, hand.asEquipmentSlot()); if (weapon.isEmpty()) { break; -@@ -95,6 +_,11 @@ +@@ -103,6 +_,12 @@ } - protected static List draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter) { + protected static List draw(final ItemStack weapon, final ItemStack projectile, final LivingEntity shooter) { + // Paper start -+ return draw(weapon, ammo, shooter, true); ++ return draw(weapon, projectile, shooter, true); + } -+ protected static List draw(ItemStack weapon, ItemStack ammo, LivingEntity shooter, boolean consume) { ++ ++ protected static List draw(final ItemStack weapon, final ItemStack projectile, final LivingEntity shooter, final boolean consume) { + // Paper end - if (ammo.isEmpty()) { + if (projectile.isEmpty()) { return List.of(); } else { -@@ -103,7 +_,7 @@ - ItemStack itemStack = ammo.copy(); +@@ -113,7 +_,7 @@ + ItemStack projectileCopy = projectile.copy(); - for (int i1 = 0; i1 < i; i1++) { -- ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0); -+ ItemStack itemStack1 = useAmmo(weapon, i1 == 0 ? ammo : itemStack, shooter, i1 > 0 || !consume); // Paper - if (!itemStack1.isEmpty()) { - list.add(itemStack1); + for (int i = 0; i < numProjectiles; i++) { +- ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0); ++ ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0 || !consume); // Paper + if (!drawnStack.isEmpty()) { + drawn.add(drawnStack); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ServerItemCooldowns.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ServerItemCooldowns.java.patch index 3f975521c9f1..9cbecc8fa477 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ServerItemCooldowns.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ServerItemCooldowns.java.patch @@ -30,24 +30,24 @@ + } + + @Override -+ public void addCooldown(Identifier groupId, int duration, boolean callEvent) { ++ public void addCooldown(Identifier cooldownGroup, int time, boolean callEvent) { + if (callEvent) { + final io.papermc.paper.event.player.PlayerItemGroupCooldownEvent event = new io.papermc.paper.event.player.PlayerItemGroupCooldownEvent( + this.player.getBukkitEntity(), -+ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(groupId), -+ duration ++ org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cooldownGroup), ++ time + ); + if (!event.callEvent()) { -+ this.player.connection.send(new ClientboundCooldownPacket(groupId, this.getCurrentCooldown(groupId))); ++ this.player.connection.send(new ClientboundCooldownPacket(cooldownGroup, this.getCurrentCooldown(cooldownGroup))); + return; + } + -+ duration = event.getCooldown(); ++ time = event.getCooldown(); + } -+ super.addCooldown(groupId, duration, false); ++ super.addCooldown(cooldownGroup, time, false); + } + // Paper end - Add PlayerItemCooldownEvent + @Override - protected void onCooldownStarted(Identifier group, int cooldown) { - super.onCooldownStarted(group, cooldown); + protected void onCooldownStarted(final Identifier cooldownGroup, final int duration) { + super.onCooldownStarted(cooldownGroup, duration); diff --git a/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch index 01d29fae90da..97a7cf9785fa 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch @@ -2,32 +2,32 @@ +++ b/net/minecraft/world/item/ShovelItem.java @@ -45,20 +_,29 @@ Player player = context.getPlayer(); - BlockState blockState1 = FLATTENABLES.get(blockState.getBlock()); - BlockState blockState2 = null; + BlockState newState = FLATTENABLES.get(blockState.getBlock()); + BlockState updatedState = null; + Runnable afterAction = null; // Paper - if (blockState1 != null && level.getBlockState(clickedPos.above()).isAir()) { -- level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); -+ afterAction = () -> level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper - blockState2 = blockState1; + if (newState != null && level.getBlockState(pos.above()).isAir()) { +- level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); ++ afterAction = () -> level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper + updatedState = newState; } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { + afterAction = () -> { // Paper if (!level.isClientSide()) { - level.levelEvent(null, LevelEvent.SOUND_EXTINGUISH_FIRE, clickedPos, 0); + level.levelEvent(null, LevelEvent.SOUND_EXTINGUISH_FIRE, pos, 0); } - CampfireBlock.dowse(context.getPlayer(), level, clickedPos, blockState); + CampfireBlock.dowse(context.getPlayer(), level, pos, blockState); + }; // Paper - blockState2 = blockState.setValue(CampfireBlock.LIT, false); + updatedState = blockState.setValue(CampfireBlock.LIT, false); } - if (blockState2 != null) { + if (updatedState != null) { if (!level.isClientSide()) { + // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), clickedPos, blockState2)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, updatedState)) { + return InteractionResult.PASS; + } + afterAction.run(); + // Paper end - level.setBlock(clickedPos, blockState2, Block.UPDATE_ALL_IMMEDIATE); - level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, blockState2)); + level.setBlock(pos, updatedState, Block.UPDATE_ALL_IMMEDIATE); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, updatedState)); if (player != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/SignItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/SignItem.java.patch index eb805f28709f..55d79b84c5e4 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/SignItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/SignItem.java.patch @@ -5,18 +5,18 @@ public class SignItem extends StandingAndWallBlockItem { + public static BlockPos openSign; // CraftBukkit - public SignItem(Block standingBlock, Block wallBlock, Item.Properties properties) { - super(standingBlock, wallBlock, Direction.DOWN, properties); + public SignItem(final Block sign, final Block wallSign, final Item.Properties properties) { + super(sign, wallSign, Direction.DOWN, properties); } -@@ -27,7 +_,10 @@ +@@ -29,7 +_,10 @@ && player != null - && level.getBlockEntity(pos) instanceof SignBlockEntity signBlockEntity - && level.getBlockState(pos).getBlock() instanceof SignBlock signBlock) { -- signBlock.openTextEdit(player, signBlockEntity, true); + && level.getBlockEntity(pos) instanceof SignBlockEntity signEntity + && level.getBlockState(pos).getBlock() instanceof SignBlock sign) { +- sign.openTextEdit(player, signEntity, true); + // CraftBukkit start - SPIGOT-4678 -+ // signBlock.openTextEdit(player, signBlockEntity, true); ++ // sign.openTextEdit(player, signEntity, true); + SignItem.openSign = pos; + // CraftBukkit end } - return flag; + return success; diff --git a/paper-server/patches/sources/net/minecraft/world/item/SnowballItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/SnowballItem.java.patch index 5f8381a2e0d5..0f4722e438a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/SnowballItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/SnowballItem.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/item/SnowballItem.java +++ b/net/minecraft/world/item/SnowballItem.java -@@ -23,22 +_,41 @@ +@@ -23,22 +_,40 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); - level.playSound( - null, - player.getX(), @@ -16,19 +16,18 @@ - ); + // CraftBukkit start - moved down if (level instanceof ServerLevel serverLevel) { -- Projectile.spawnProjectileFromRotation(Snowball::new, serverLevel, itemInHand, player, 0.0F, PROJECTILE_SHOOT_POWER, 1.0F); +- Projectile.spawnProjectileFromRotation(Snowball::new, serverLevel, itemStack, player, 0.0F, 1.5F, 1.0F); + // Paper start - PlayerLaunchProjectileEvent -+ final Projectile.Delayed snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemInHand, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F); -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity()); ++ final Projectile.Delayed snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemStack, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity()); + if (event.callEvent() && snowball.attemptSpawn()) { + player.awardStat(Stats.ITEM_USED.get(this)); + if (event.shouldConsume()) { -+ itemInHand.consume(1, player); ++ itemStack.consume(1, player); + } else { + player.containerMenu.forceHeldSlot(hand); + } + // Paper end - PlayerLaunchProjectileEvent -+ + level.playSound( + null, + player.getX(), @@ -49,9 +48,9 @@ } - player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- itemStack.consume(1, player); + // Paper - PlayerLaunchProjectileEvent - moved up -+ // itemInHand.consume(1, player); // CraftBukkit - moved up ++ // itemStack.consume(1, player); // CraftBukkit - moved up return InteractionResult.SUCCESS; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch index 9ce8994289c2..55e947834b83 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/item/SpawnEggItem.java +++ b/net/minecraft/world/item/SpawnEggItem.java -@@ -69,6 +_,7 @@ +@@ -61,6 +_,7 @@ return InteractionResult.FAIL; } else { + if (level.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation - spawner.setEntityId(type, level.getRandom()); - level.sendBlockUpdated(clickedPos, blockState, blockState, Block.UPDATE_ALL); - level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, clickedPos); -@@ -96,7 +_,7 @@ - EntityType type = this.getType(stack); + spawnerHolder.setEntityId(type, level.getRandom()); + level.sendBlockUpdated(pos, blockState, blockState, Block.UPDATE_ALL); + level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, pos); +@@ -91,7 +_,7 @@ + EntityType type = getType(itemStack); if (type == null) { return InteractionResult.FAIL; - } else if (!type.isAllowedInPeaceful() && level.getDifficulty() == Difficulty.PEACEFUL) { -+ } else if (!type.isAllowedInPeaceful(stack.get(DataComponents.ENTITY_DATA).getUnsafe()) && level.getDifficulty() == Difficulty.PEACEFUL) { // Paper - check peaceful override ++ } else if (!type.isAllowedInPeaceful(itemStack.get(DataComponents.ENTITY_DATA).getUnsafe()) && level.getDifficulty() == Difficulty.PEACEFUL) { // Paper - check peaceful override return InteractionResult.FAIL; } else { - if (type.spawn((ServerLevel)level, stack, owner, pos, EntitySpawnReason.SPAWN_ITEM_USE, shouldOffsetY, shouldOffsetYMore) != null) { -@@ -178,7 +_,7 @@ + if (type.spawn((ServerLevel)level, itemStack, user, spawnPos, EntitySpawnReason.SPAWN_ITEM_USE, tryMoveDown, movedUp) != null) { +@@ -163,7 +_,7 @@ } else { - breedOffspring.snapTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F); - breedOffspring.applyComponentsFromItemStack(stack); -- level.addFreshEntityWithPassengers(breedOffspring); -+ level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit - stack.consume(1, player); - return Optional.of(breedOffspring); + offspring.snapTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F); + offspring.applyComponentsFromItemStack(spawnEggStack); +- level.addFreshEntityWithPassengers(offspring); ++ level.addFreshEntityWithPassengers(offspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit + spawnEggStack.consume(1, player); + return Optional.of(offspring); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/SplashPotionItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/SplashPotionItem.java.patch index 06950791a904..95cf5f1c94f9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/SplashPotionItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/SplashPotionItem.java.patch @@ -3,7 +3,7 @@ @@ -19,6 +_,10 @@ @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + // Paper start - PlayerLaunchProjectileEvent + final InteractionResult wrapper = super.use(level, player, hand); + if (wrapper instanceof InteractionResult.Fail) return wrapper; diff --git a/paper-server/patches/sources/net/minecraft/world/item/StandingAndWallBlockItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/StandingAndWallBlockItem.java.patch index 90f8211a9a80..1e29b0beab7f 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/StandingAndWallBlockItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/StandingAndWallBlockItem.java.patch @@ -4,17 +4,17 @@ } } -- return blockState != null && level.isUnobstructed(blockState, clickedPos, CollisionContext.empty()) ? blockState : null; -+ // return blockState != null && level.isUnobstructed(blockState, clickedPos, CollisionContext.empty()) ? blockState : null; +- return stateForPlacement != null && level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty()) ? stateForPlacement : null; ++ // return stateForPlacement != null && level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty()) ? stateForPlacement : null; + // CraftBukkit start -+ if (blockState != null) { -+ boolean defaultReturn = level.isUnobstructed(blockState, clickedPos, CollisionContext.empty()); ++ if (stateForPlacement != null) { ++ boolean defaultReturn = level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty()); + org.bukkit.entity.Player player = (context.getPlayer() instanceof net.minecraft.server.level.ServerPlayer serverPlayer) ? serverPlayer.getBukkitEntity() : null; + -+ org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent(org.bukkit.craftbukkit.block.CraftBlock.at(context.getLevel(), clickedPos), player, org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(blockState), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent ++ org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent(org.bukkit.craftbukkit.block.CraftBlock.at(context.getLevel(), pos), player, stateForPlacement.asBlockData(), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent + context.getLevel().getCraftServer().getPluginManager().callEvent(event); + -+ return (event.isBuildable()) ? blockState : null; ++ return (event.isBuildable()) ? stateForPlacement : null; + } else { + return null; + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch index 998923f073a3..5d405d26804c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/item/ThrowablePotionItem.java +++ b/net/minecraft/world/item/ThrowablePotionItem.java @@ -23,11 +_,24 @@ - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack itemStack = player.getItemInHand(hand); if (level instanceof ServerLevel serverLevel) { -- Projectile.spawnProjectileFromRotation(this::createPotion, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F); +- Projectile.spawnProjectileFromRotation(this::createPotion, serverLevel, itemStack, player, -20.0F, 0.5F, 1.0F); + // Paper start - PlayerLaunchProjectileEvent -+ final Projectile.Delayed thrownPotion = Projectile.spawnProjectileFromRotationDelayed(this::createPotion, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F); -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity()); ++ final Projectile.Delayed thrownPotion = Projectile.spawnProjectileFromRotationDelayed(this::createPotion, serverLevel, itemStack, player, -20.0F, 0.5F, 1.0F); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity()); + if (event.callEvent() && thrownPotion.attemptSpawn()) { + if (event.shouldConsume()) { -+ itemInHand.consume(1, player); ++ itemStack.consume(1, player); + } else { + player.containerMenu.forceHeldSlot(hand); + } @@ -22,7 +22,7 @@ } player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- itemStack.consume(1, player); + // Paper - PlayerLaunchProjectileEvent - move up return InteractionResult.SUCCESS; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch index 34ac38899186..786ea731da41 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch @@ -1,52 +1,52 @@ --- a/net/minecraft/world/item/TridentItem.java +++ b/net/minecraft/world/item/TridentItem.java -@@ -79,18 +_,38 @@ - .orElse(SoundEvents.TRIDENT_THROW); - player.awardStat(Stats.ITEM_USED.get(this)); - if (level instanceof ServerLevel serverLevel) { -- stack.hurtWithoutBreaking(1, player); -+ // stack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down - if (tridentSpinAttackStrength == 0.0F) { -- ItemStack itemStack = stack.consumeAndReturn(1, player); -- ThrownTrident thrownTrident = Projectile.spawnProjectileFromRotation( -+ ItemStack itemStack = stack.copyWithCount(1); // Paper -+ Projectile.Delayed tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent( - ThrownTrident::new, serverLevel, itemStack, player, 0.0F, 2.5F, 1.0F - ); -+ // Paper start - PlayerLaunchProjectileEvent -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity()); -+ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) { -+ // CraftBukkit start -+ // Paper end - PlayerLaunchProjectileEvent -+ return false; -+ } -+ ThrownTrident thrownTrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent -+ if (event.shouldConsume()) { -+ itemStack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent - use itemStack; pickup item damage -+ } -+ thrownTrident.pickupItemStack = itemStack.copy(); // SPIGOT-4511 update since damage call moved - use itemStack; count = 1 -+ if (event.shouldConsume()) { -+ stack.consume(1, player); -+ } -+ // CraftBukkit end - if (player.hasInfiniteMaterials()) { - thrownTrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - } +@@ -78,18 +_,38 @@ + .orElse(SoundEvents.TRIDENT_THROW); + player.awardStat(Stats.ITEM_USED.get(this)); + if (level instanceof ServerLevel serverLevel) { +- itemStack.hurtWithoutBreaking(1, player); ++ // itemStack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down + if (riptideStrength == 0.0F) { +- ItemStack thrownItemStack = itemStack.consumeAndReturn(1, player); +- ThrownTrident trident = Projectile.spawnProjectileFromRotation( ++ ItemStack thrownItemStack = itemStack.copyWithCount(1); // Paper ++ Projectile.Delayed tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent( + ThrownTrident::new, serverLevel, thrownItemStack, player, 0.0F, 2.5F, 1.0F + ); ++ // Paper start - PlayerLaunchProjectileEvent ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity()); ++ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) { ++ // CraftBukkit start ++ // Paper end - PlayerLaunchProjectileEvent ++ return false; ++ } ++ ThrownTrident trident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent ++ if (event.shouldConsume()) { ++ thrownItemStack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent - use thrownItemStack; pickup item damage ++ } ++ trident.pickupItemStack = thrownItemStack.copy(); // SPIGOT-4511 update since damage call moved - use thrownItemStack; count = 1 ++ if (event.shouldConsume()) { ++ itemStack.consume(1, player); ++ } ++ // CraftBukkit end + if (player.hasInfiniteMaterials()) { + trident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; + } - level.playSound(null, thrownTrident, holder.value(), SoundSource.PLAYERS, 1.0F, 1.0F); - return true; -+ // CraftBukkit start - SPIGOT-5458 also need in this branch :( -+ } else { -+ stack.hurtWithoutBreaking(1, player); -+ // CraftBukkit end + level.playSound(null, trident, sound.value(), SoundSource.PLAYERS, 1.0F, 1.0F); + return true; ++ // CraftBukkit start - SPIGOT-5458 also need in this branch :( ++ } else { ++ itemStack.hurtWithoutBreaking(1, player); ++ // CraftBukkit end + } } - } -@@ -104,6 +_,7 @@ - f *= tridentSpinAttackStrength / squareRoot; - f1 *= tridentSpinAttackStrength / squareRoot; - f2 *= tridentSpinAttackStrength / squareRoot; -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, stack, f, f1, f2)) return false; // Paper - Add player riptide event - player.push(f, f1, f2); - player.startAutoSpinAttack(20, 8.0F, stack); - if (player.onGround()) { +@@ -103,6 +_,7 @@ + xd *= riptideStrength / dist; + yd *= riptideStrength / dist; + zd *= riptideStrength / dist; ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, itemStack, xd, yd, zd)) return false; // Paper - Add player riptide event + player.push(xd, yd, zd); + player.startAutoSpinAttack(20, 8.0F, itemStack); + if (player.onGround()) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/WindChargeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/WindChargeItem.java.patch index ad11eafc3829..a68f6c793efe 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/WindChargeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/WindChargeItem.java.patch @@ -1,30 +1,30 @@ --- a/net/minecraft/world/item/WindChargeItem.java +++ b/net/minecraft/world/item/WindChargeItem.java @@ -28,7 +_,7 @@ - public InteractionResult use(Level level, Player player, InteractionHand hand) { - ItemStack itemInHand = player.getItemInHand(hand); + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); if (level instanceof ServerLevel serverLevel) { - Projectile.spawnProjectileFromRotation( + final Projectile.Delayed windCharge = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent - (level1, owner, spawnedFrom) -> new WindCharge(player, level, player.position().x(), player.getEyePosition().y(), player.position().z()), + (source, l, itemStack) -> new WindCharge(player, level, player.position().x(), player.getEyePosition().y(), player.position().z()), serverLevel, - itemInHand, + stack, @@ -37,6 +_,22 @@ - PROJECTILE_SHOOT_POWER, + 1.5F, 1.0F ); + // Paper start - PlayerLaunchProjectileEvent -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) windCharge.projectile().getBukkitEntity()); ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) windCharge.projectile().getBukkitEntity()); + if (!event.callEvent() || !windCharge.attemptSpawn()) { + player.containerMenu.forceHeldSlot(hand); + if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { -+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(itemInHand), 0)); // prevent visual desync of cooldown on the slot ++ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundCooldownPacket(player.getCooldowns().getCooldownGroup(stack), 0)); // prevent visual desync of cooldown on the slot + } + return InteractionResult.FAIL; + } + + player.awardStat(Stats.ITEM_USED.get(this)); -+ if (event.shouldConsume()) itemInHand.consume(1, player); ++ if (event.shouldConsume()) stack.consume(1, player); + else if (!player.hasInfiniteMaterials()) { + player.containerMenu.forceHeldSlot(hand); + } @@ -37,7 +37,7 @@ 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F) ); - player.awardStat(Stats.ITEM_USED.get(this)); -- itemInHand.consume(1, player); +- stack.consume(1, player); + // Paper - PlayerLaunchProjectileEvent; moved up return InteractionResult.SUCCESS; } diff --git a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch index f81ac811fa58..03fbf04cd2f2 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch @@ -6,44 +6,44 @@ private final List> containerMixes; + private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes - PotionBrewing(List containers, List> potionMixes, List> containerMixes) { - this.containers = containers; -@@ -27,7 +_,7 @@ + private PotionBrewing( + final List containers, final List> potionMixes, final List> containerMixes +@@ -29,7 +_,7 @@ } - public boolean isIngredient(ItemStack stack) { -- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack); -+ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes + public boolean isIngredient(final ItemStack ingredient) { +- return this.isContainerIngredient(ingredient) || this.isPotionIngredient(ingredient); ++ return this.isContainerIngredient(ingredient) || this.isPotionIngredient(ingredient) || this.isCustomIngredient(ingredient); // Paper - Custom Potion Mixes } - private boolean isContainer(ItemStack stack) { -@@ -71,6 +_,11 @@ + private boolean isContainer(final ItemStack input) { +@@ -73,6 +_,11 @@ } - public boolean hasMix(ItemStack potion, ItemStack ingredient) { + public boolean hasMix(final ItemStack source, final ItemStack ingredient) { + // Paper start - Custom Potion Mixes -+ if (this.hasCustomMix(potion, ingredient)) { ++ if (this.hasCustomMix(source, ingredient)) { + return true; + } + // Paper end - Custom Potion Mixes - return this.isContainer(potion) && (this.hasContainerMix(potion, ingredient) || this.hasPotionMix(potion, ingredient)); + return this.isContainer(source) && (this.hasContainerMix(source, ingredient) || this.hasPotionMix(source, ingredient)); } -@@ -103,6 +_,13 @@ - if (potion.isEmpty()) { - return potion; - } else { -+ // Paper start - Custom Potion Mixes -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.input().test(potion) && mix.ingredient().test(ingredient)) { -+ return mix.result().copy(); +@@ -109,6 +_,13 @@ + if (potion.isEmpty()) { + return source; + } else { ++ // Paper start - Custom Potion Mixes ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(source) && mix.ingredient().test(ingredient)) { ++ return mix.result().copy(); ++ } + } -+ } -+ // Paper end - Custom Potion Mixes - Optional> optional = potion.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion(); - if (optional.isEmpty()) { - return potion; -@@ -189,6 +_,50 @@ ++ // Paper end - Custom Potion Mixes + for (PotionBrewing.Mix mix : this.containerMixes) { + if (source.is(mix.from) && mix.ingredient.test(ingredient)) { + return PotionContents.createItemStack(mix.to.value(), potion.get()); +@@ -191,6 +_,50 @@ builder.addMix(Potions.AWKWARD, Items.PHANTOM_MEMBRANE, Potions.SLOW_FALLING); builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionContents.java.patch b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionContents.java.patch index 95e0c047a69e..9c5ba623b7c6 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionContents.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/item/alchemy/PotionContents.java @@ -158,7 +_,7 @@ if (effect.getEffect().value().isInstantenous()) { - effect.getEffect().value().applyInstantenousEffect(serverLevel, player1, player1, entity, effect.getAmplifier(), 1.0); + effect.getEffect().value().applyInstantenousEffect(serverLevel, player, player, entity, effect.getAmplifier(), 1.0); } else { - entity.addEffect(effect); + entity.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_DRINK); // CraftBukkit diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/AttackRange.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/AttackRange.java.patch index a5c1424febaa..ce5e2600f932 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/AttackRange.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/AttackRange.java.patch @@ -3,22 +3,22 @@ @@ -25,14 +_,15 @@ import net.minecraft.world.phys.Vec3; - public record AttackRange(float minRange, float maxRange, float minCreativeRange, float maxCreativeRange, float hitboxMargin, float mobFactor) { + public record AttackRange(float minReach, float maxReach, float minCreativeReach, float maxCreativeReach, float hitboxMargin, float mobFactor) { + public static final AttackRange CODEC_DEFAULT = new AttackRange(0.0F, 3.0F, 0.0F, 5.0F, 0.3F, 1.0F); // Paper - add back defaults instance public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( -- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_reach", 0.0F).forGetter(AttackRange::minRange), -- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_reach", 3.0F).forGetter(AttackRange::maxRange), -- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_creative_reach", 0.0F).forGetter(AttackRange::minCreativeRange), -- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_creative_reach", 5.0F).forGetter(AttackRange::maxCreativeRange), + i -> i.group( +- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_reach", 0.0F).forGetter(AttackRange::minReach), +- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_reach", 3.0F).forGetter(AttackRange::maxReach), +- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_creative_reach", 0.0F).forGetter(AttackRange::minCreativeReach), +- ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_creative_reach", 5.0F).forGetter(AttackRange::maxCreativeReach), - ExtraCodecs.floatRange(0.0F, 1.0F).optionalFieldOf("hitbox_margin", 0.3F).forGetter(AttackRange::hitboxMargin), - Codec.floatRange(0.0F, 2.0F).optionalFieldOf("mob_factor", 1.0F).forGetter(AttackRange::mobFactor) -+ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_reach", 0.0F).forGetter(AttackRange::minRange), // Paper - diff on change: used in CODEC_DEFAULT above -+ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_reach", 3.0F).forGetter(AttackRange::maxRange), // Paper - diff on change: used in CODEC_DEFAULT above -+ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_creative_reach", 0.0F).forGetter(AttackRange::minCreativeRange), // Paper - diff on change: used in CODEC_DEFAULT above -+ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_creative_reach", 5.0F).forGetter(AttackRange::maxCreativeRange), // Paper - diff on change: used in CODEC_DEFAULT above ++ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_reach", 0.0F).forGetter(AttackRange::minReach), // Paper - diff on change: used in CODEC_DEFAULT above ++ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_reach", 3.0F).forGetter(AttackRange::maxReach), // Paper - diff on change: used in CODEC_DEFAULT above ++ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("min_creative_reach", 0.0F).forGetter(AttackRange::minCreativeReach), // Paper - diff on change: used in CODEC_DEFAULT above ++ ExtraCodecs.floatRange(0.0F, 64.0F).optionalFieldOf("max_creative_reach", 5.0F).forGetter(AttackRange::maxCreativeReach), // Paper - diff on change: used in CODEC_DEFAULT above + ExtraCodecs.floatRange(0.0F, 1.0F).optionalFieldOf("hitbox_margin", 0.3F).forGetter(AttackRange::hitboxMargin), // Paper - diff on change: used in CODEC_DEFAULT above + Codec.floatRange(0.0F, 2.0F).optionalFieldOf("mob_factor", 1.0F).forGetter(AttackRange::mobFactor) // Paper - diff on change: used in CODEC_DEFAULT above ) - .apply(instance, AttackRange::new) + .apply(i, AttackRange::new) ); diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/BlocksAttacks.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/BlocksAttacks.java.patch index 568583af602b..44f40b7b6c36 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/BlocksAttacks.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/BlocksAttacks.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/item/component/BlocksAttacks.java +++ b/net/minecraft/world/item/component/BlocksAttacks.java -@@ -86,11 +_,15 @@ +@@ -85,11 +_,15 @@ ); } -- public void disable(ServerLevel level, LivingEntity entity, float duration, ItemStack stack) { -+ public void disable(ServerLevel level, LivingEntity entity, float duration, ItemStack stack, LivingEntity attacker) { // Paper - int i = this.disableBlockingForTicks(duration); - if (i > 0) { - if (entity instanceof Player player) { -- player.getCooldowns().addCooldown(stack, i); +- public void disable(final ServerLevel level, final LivingEntity user, final float baseSeconds, final ItemStack blockingWith) { ++ public void disable(final ServerLevel level, final LivingEntity user, final float baseSeconds, final ItemStack blockingWith, LivingEntity attacker) { // Paper + int cooldownTicks = this.disableBlockingForTicks(baseSeconds); + if (cooldownTicks > 0) { + if (user instanceof Player player) { +- player.getCooldowns().addCooldown(blockingWith, cooldownTicks); + // Paper start -+ final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) player.getBukkitEntity(), attacker.getBukkitEntity(), i); ++ final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) player.getBukkitEntity(), attacker.getBukkitEntity(), cooldownTicks); + if (!shieldDisableEvent.callEvent()) return; -+ player.getCooldowns().addCooldown(stack, shieldDisableEvent.getCooldown()); ++ player.getCooldowns().addCooldown(blockingWith, shieldDisableEvent.getCooldown()); + // Paper end } - entity.stopUsingItem(); + user.stopUsingItem(); diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/BundleContents.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/BundleContents.java.patch index c5caf800fceb..2694a8259a2c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/BundleContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/BundleContents.java.patch @@ -1,38 +1,39 @@ --- a/net/minecraft/world/item/component/BundleContents.java +++ b/net/minecraft/world/item/component/BundleContents.java -@@ -25,6 +_,7 @@ - .flatXmap(BundleContents::checkAndCreate, bundleContents -> DataResult.success(bundleContents.items)); - public static final StreamCodec STREAM_CODEC = ItemStack.STREAM_CODEC +@@ -28,6 +_,7 @@ + public static final Codec CODEC = ItemStackTemplate.CODEC.listOf().xmap(BundleContents::new, contents -> contents.items); + public static final StreamCodec STREAM_CODEC = ItemStackTemplate.STREAM_CODEC .apply(ByteBufCodecs.list()) + .apply(ByteBufCodecs::increaseDepth) // Paper - Track codec depth .map(BundleContents::new, contents -> contents.items); private static final Fraction BUNDLE_IN_BUNDLE_WEIGHT = Fraction.getFraction(1, 16); private static final int NO_STACK_INDEX = -1; -@@ -76,6 +_,12 @@ - return !stack.isEmpty() && stack.getItem().canFitInsideContainerItems(); +@@ -80,6 +_,13 @@ + return !itemToAdd.isEmpty() && itemToAdd.getItem().canFitInsideContainerItems(); } + // Paper start - correct bundle inventory action + public int getMaxAmountToAdd(final ItemStack stack) { -+ return Mutable.getMaxAmountToAdd(stack, this.weight); ++ DataResult weight = this.weight(); ++ return weight.isError() ? 0 : Mutable.getMaxAmountToAdd(stack, weight.getOrThrow()); + } + // Paper end - correct bundle inventory action + public int getNumberOfItemsToShow() { - int size = this.size(); - int i = size > 12 ? 11 : 12; -@@ -171,7 +_,13 @@ + int numberOfItemStacks = this.size(); + int availableItemsToShow = numberOfItemStacks > 12 ? 11 : 12; +@@ -179,6 +_,14 @@ + Fraction remainingWeight = Fraction.ONE.subtract(this.weight); + return Math.max(remainingWeight.divideBy(itemWeight).intValue(), 0); } - - public int getMaxAmountToAdd(ItemStack stack) { -- Fraction fraction = Fraction.ONE.subtract(this.weight); ++ + // Paper start - correct bundle inventory action + // Static overload to easily compute this value without the need for an instance of mutable. -+ return getMaxAmountToAdd(stack, this.weight); -+ } + static int getMaxAmountToAdd(final ItemStack stack, final Fraction weight) { -+ Fraction fraction = Fraction.ONE.subtract(weight); ++ Fraction remainingWeight = Fraction.ONE.subtract(weight); ++ return Math.max(remainingWeight.divideBy(BundleContents.getWeight(stack).getOrThrow()).intValue(), 0); ++ } + // Paper end - correct bundle inventory action - return Math.max(fraction.divideBy(BundleContents.getWeight(stack)).intValue(), 0); - } + public int tryInsert(final ItemStack itemsToAdd) { + if (!BundleContents.canItemBeInBundle(itemsToAdd)) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ChargedProjectiles.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ChargedProjectiles.java.patch index e8043215a614..6055dd9917a3 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ChargedProjectiles.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ChargedProjectiles.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/item/component/ChargedProjectiles.java +++ b/net/minecraft/world/item/component/ChargedProjectiles.java -@@ -22,6 +_,7 @@ - .xmap(ChargedProjectiles::new, chargedProjectiles -> chargedProjectiles.items); - public static final StreamCodec STREAM_CODEC = ItemStack.STREAM_CODEC +@@ -21,6 +_,7 @@ + public static final Codec CODEC = ItemStackTemplate.CODEC.listOf().xmap(ChargedProjectiles::new, projectiles -> projectiles.items); + public static final StreamCodec STREAM_CODEC = ItemStackTemplate.STREAM_CODEC .apply(ByteBufCodecs.list()) + .apply(ByteBufCodecs::increaseDepth) // Paper - Track codec depth - .map(ChargedProjectiles::new, chargedProjectiles -> chargedProjectiles.items); - private final List items; + .map(ChargedProjectiles::new, projectiles -> projectiles.items); + public static ChargedProjectiles of(final ItemStackTemplate stack) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch index 6c13e5899a08..74f0fe8217b3 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch @@ -2,9 +2,9 @@ +++ b/net/minecraft/world/item/component/Consumable.java @@ -84,13 +_,35 @@ - stack.getAllOfType(ConsumableListener.class).forEach(consumableListener -> consumableListener.onConsume(level, entity, stack, this)); + stack.getAllOfType(ConsumableListener.class).forEach(component -> component.onConsume(level, user, stack, this)); if (!level.isClientSide()) { -- this.onConsumeEffects.forEach(consumeEffect -> consumeEffect.apply(level, stack, entity)); +- this.onConsumeEffects.forEach(action -> action.apply(level, stack, user)); + // CraftBukkit start + org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause; + if (stack.is(net.minecraft.world.item.Items.MILK_BUCKET)) { @@ -15,12 +15,12 @@ + cause = org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD; + } + -+ this.onConsumeEffects.forEach(consumeEffect -> consumeEffect.apply(level, stack, entity, cause)); ++ this.onConsumeEffects.forEach(consumeEffect -> consumeEffect.apply(level, stack, user, cause)); + // CraftBukkit end } - entity.gameEvent(this.animation == ItemUseAnimation.DRINK ? GameEvent.DRINK : GameEvent.EAT); - stack.consume(1, entity); + user.gameEvent(this.animation == ItemUseAnimation.DRINK ? GameEvent.DRINK : GameEvent.EAT); + stack.consume(1, user); return stack; } + @@ -35,5 +35,5 @@ + } + // CraftBukkit end - public boolean canConsume(LivingEntity entity, ItemStack stack) { + public boolean canConsume(final LivingEntity user, final ItemStack stack) { FoodProperties foodProperties = stack.get(DataComponents.FOOD); diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch index a47c2b2a62a1..65cfa2773d02 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ConsumableListener.java.patch @@ -3,7 +3,7 @@ @@ -6,4 +_,6 @@ public interface ConsumableListener { - void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable); + void onConsume(final Level level, final LivingEntity user, final ItemStack stack, final Consumable consumable); + + default void cancelUsingItem(net.minecraft.server.level.ServerPlayer player, ItemStack stack, java.util.List> collectedPackets) {} // CraftBukkit // Paper - properly resend entities - collect packets for bundle } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/CustomData.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/CustomData.java.patch index 6173a85d3c8e..80ddb7fcfc87 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/CustomData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/CustomData.java.patch @@ -36,4 +36,4 @@ + // Paper end - expose unsafe internal compound tag for read only access @Override - public boolean equals(Object other) { + public boolean equals(final Object obj) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/DeathProtection.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/DeathProtection.java.patch index b2efb28173e3..a00b90d9d64c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/DeathProtection.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/DeathProtection.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/item/component/DeathProtection.java @@ -37,7 +_,7 @@ - public void applyEffects(ItemStack stack, LivingEntity entity) { - for (ConsumeEffect consumeEffect : this.deathEffects) { -- consumeEffect.apply(entity.level(), stack, entity); -+ consumeEffect.apply(entity.level(), stack, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM); // CraftBukkit + public void applyEffects(final ItemStack itemStack, final LivingEntity entity) { + for (ConsumeEffect effect : this.deathEffects) { +- effect.apply(entity.level(), itemStack, entity); ++ effect.apply(entity.level(), itemStack, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ItemContainerContents.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ItemContainerContents.java.patch index 03cce7d7e33b..ba89655d57df 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ItemContainerContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ItemContainerContents.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/item/component/ItemContainerContents.java +++ b/net/minecraft/world/item/component/ItemContainerContents.java -@@ -28,6 +_,7 @@ - .xmap(ItemContainerContents::fromSlots, ItemContainerContents::asSlots); - public static final StreamCodec STREAM_CODEC = ItemStack.OPTIONAL_STREAM_CODEC - .apply(ByteBufCodecs.list(256)) +@@ -31,6 +_,7 @@ + public static final StreamCodec STREAM_CODEC = ItemStackTemplate.STREAM_CODEC + .apply(ByteBufCodecs::optional) + .>>apply(ByteBufCodecs.list(256)) + .apply(ByteBufCodecs::increaseDepth) // Paper - Track codec depth - .map(ItemContainerContents::new, contents -> contents.items); - public final NonNullList items; + .map(ItemContainerContents::new, c -> c.items); + public final List> items; private final int hashCode; diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch index 3bad9d4109b1..6e6193d90686 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/OminousBottleAmplifier.java.patch @@ -3,10 +3,10 @@ @@ -29,8 +_,15 @@ @Override - public void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable) { -- entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); + public void onConsume(final Level level, final LivingEntity user, final ItemStack stack, final Consumable consumable) { +- user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); - } -+ entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below ++ user.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below + } + + // Paper start - properly resend entities - collect packets for bundle @@ -17,4 +17,4 @@ + // Paper end - properly resend entities - collect packets for bundle @Override - public void addToTooltip(Item.TooltipContext context, Consumer tooltipAdder, TooltipFlag flag, DataComponentGetter componentGetter) { + public void addToTooltip( diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch index 0fb4790ff20a..5f1e7579685c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/item/component/ResolvableProfile.java +++ b/net/minecraft/world/item/component/ResolvableProfile.java @@ -46,7 +_,7 @@ - private static ResolvableProfile create(Either contents, PlayerSkin.Patch skinPatch) { - return contents.map( - gameProfile -> new ResolvableProfile.Static(Either.left(gameProfile), skinPatch), + private static ResolvableProfile create(final Either value, final PlayerSkin.Patch patch) { + return value.map( + full -> new ResolvableProfile.Static(Either.left(full), patch), - partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() + partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() // Paper - diff on change - heuristic for dynamic vs static resolvable profile - used in CraftPlayerProfile#buildResolvable ? partial.name - .map(string -> new ResolvableProfile.Dynamic(Either.left(string), skinPatch)) - .orElseGet(() -> new ResolvableProfile.Dynamic(Either.right(partial.id.get()), skinPatch)) -@@ -139,9 +_,10 @@ - instance -> instance.group( + .map(s -> new ResolvableProfile.Dynamic(Either.left(s), patch)) + .orElseGet(() -> new ResolvableProfile.Dynamic(Either.right(partial.id.get()), patch)) +@@ -140,9 +_,10 @@ + i -> i.group( ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile.Partial::name), UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile.Partial::id), + UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", PropertyMap.EMPTY).forGetter(ResolvableProfile.Partial::properties) ) -- .apply(instance, ResolvableProfile.Partial::new) -+ .apply(instance, (name, uuid, uuid2, propertyMap) -> new ResolvableProfile.Partial(name, uuid2.or(() -> uuid), propertyMap)) // Paper +- .apply(i, ResolvableProfile.Partial::new) ++ .apply(i, (name, uuid, uuid2, propertyMap) -> new ResolvableProfile.Partial(name, uuid2.or(() -> uuid), propertyMap)) // Paper ); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.PLAYER_NAME.apply(ByteBufCodecs::optional), diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch index c6c3fb78838b..d2a2de9725b6 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/SuspiciousStewEffects.java.patch @@ -14,5 +14,5 @@ + // CraftBukkit end + @Override - public void addToTooltip(Item.TooltipContext context, Consumer tooltipAdder, TooltipFlag flag, DataComponentGetter componentGetter) { - if (flag.isCreative()) { + public void addToTooltip( + final Item.TooltipContext context, final Consumer consumer, final TooltipFlag flag, final DataComponentGetter components diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch index cf02814d415d..2d3b87168c1e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/item/component/TypedEntityData.java +++ b/net/minecraft/world/item/component/TypedEntityData.java @@ -84,6 +_,32 @@ - this.tag = stripId(tag); + this.tag = stripId(data); } + // Paper start - utils for item meta @@ -25,20 +25,20 @@ + + public CompoundTag copyTagWithBlockEntityId() { + final CompoundTag tag = this.tag.copy(); -+ tag.putString("id", net.minecraft.world.level.block.entity.BlockEntityType.getKey((net.minecraft.world.level.block.entity.BlockEntityType) this.type).toString()); ++ tag.putString("id", net.minecraft.core.registries.BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey((net.minecraft.world.level.block.entity.BlockEntityType) this.type).toString()); + return tag; + } + // Paper end - utils for item meta + - public static TypedEntityData of(T type, CompoundTag tag) { - return new TypedEntityData<>(type, tag); + public static TypedEntityData of(final T type, final CompoundTag data) { + return new TypedEntityData<>(type, data); } -@@ -181,7 +_,7 @@ - public void addToTooltip(Item.TooltipContext context, Consumer tooltipAdder, TooltipFlag flag, DataComponentGetter componentGetter) { +@@ -182,7 +_,7 @@ + ) { if (this.type.getClass() == EntityType.class) { - EntityType entityType = (EntityType)this.type; -- if (context.isPeaceful() && !entityType.isAllowedInPeaceful()) { -+ if (context.isPeaceful() && !entityType.isTypeAllowedInPeaceful()) { // Paper - do not check entity data for peaceful override - match client as close as possible for compute tooltip api - tooltipAdder.accept(Component.translatable("item.spawn_egg.peaceful").withStyle(ChatFormatting.RED)); + EntityType type = (EntityType)this.type; +- if (context.isPeaceful() && !type.isAllowedInPeaceful()) { ++ if (context.isPeaceful() && !type.isTypeAllowedInPeaceful()) { // Paper - do not check entity data for peaceful override - match client as close as possible for compute tooltip api + consumer.accept(Component.translatable("item.spawn_egg.peaceful").withStyle(ChatFormatting.RED)); } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/UseRemainder.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/UseRemainder.java.patch index a10f28000b40..d7d93ef8cb7b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/UseRemainder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/UseRemainder.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/component/UseRemainder.java +++ b/net/minecraft/world/item/component/UseRemainder.java -@@ -8,7 +_,7 @@ - public record UseRemainder(ItemStack convertInto) { - public static final Codec CODEC = ItemStack.CODEC.xmap(UseRemainder::new, UseRemainder::convertInto); +@@ -9,7 +_,7 @@ + public record UseRemainder(ItemStackTemplate convertInto) { + public static final Codec CODEC = ItemStackTemplate.CODEC.xmap(UseRemainder::new, UseRemainder::convertInto); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( -- ItemStack.STREAM_CODEC, UseRemainder::convertInto, UseRemainder::new -+ ItemStack.STREAM_CODEC.apply(net.minecraft.network.codec.ByteBufCodecs::increaseDepth), UseRemainder::convertInto, UseRemainder::new // Paper - Track codec depth +- ItemStackTemplate.STREAM_CODEC, UseRemainder::convertInto, UseRemainder::new ++ ItemStackTemplate.STREAM_CODEC.apply(net.minecraft.network.codec.ByteBufCodecs::increaseDepth), UseRemainder::convertInto, UseRemainder::new // Paper - Track codec depth ); - public ItemStack convertIntoRemainder(ItemStack stack, int count, boolean hasInfiniteMaterials, UseRemainder.OnExtraCreatedRemainder onExtraCreated) { + public ItemStack convertIntoRemainder( diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/WrittenBookContent.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/WrittenBookContent.java.patch index b8d4d0c85d0e..d68b69b84b1d 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/WrittenBookContent.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/WrittenBookContent.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/component/WrittenBookContent.java +++ b/net/minecraft/world/item/component/WrittenBookContent.java -@@ -93,7 +_,7 @@ +@@ -91,7 +_,7 @@ - public static boolean resolveForItem(ItemStack stack, CommandSourceStack source, @Nullable Player player) { - WrittenBookContent writtenBookContent = stack.get(DataComponents.WRITTEN_BOOK_CONTENT); -- if (writtenBookContent != null && !writtenBookContent.resolved()) { -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && writtenBookContent != null && !writtenBookContent.resolved()) { // Paper - Disable component selector resolving in books by default - WrittenBookContent writtenBookContent1 = writtenBookContent.resolve(source, player); - if (writtenBookContent1 != null) { - stack.set(DataComponents.WRITTEN_BOOK_CONTENT, writtenBookContent1); + public static boolean resolveForItem(final ItemStack itemStack, final ResolutionContext context, final HolderLookup.Provider registries) { + WrittenBookContent content = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT); +- if (content != null && !content.resolved()) { ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && content != null && !content.resolved()) { // Paper - Disable component selector resolving in books by default + WrittenBookContent resolvedContent = content.resolve(context, registries); + if (resolvedContent != null) { + itemStack.set(DataComponents.WRITTEN_BOOK_CONTENT, resolvedContent); diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch index 4d29a75fd94c..412ccec493e3 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch @@ -4,16 +4,16 @@ } @Override -- public boolean apply(Level level, ItemStack stack, LivingEntity entity) { -+ public boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { // CraftBukkit - if (entity.getRandom().nextFloat() >= this.probability) { +- public boolean apply(final Level level, final ItemStack stack, final LivingEntity user) { ++ public boolean apply(final Level level, final ItemStack stack, final LivingEntity user, final org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { // CraftBukkit + if (user.getRandom().nextFloat() >= this.probability) { return false; } else { - boolean flag = false; + boolean anyApplied = false; - for (MobEffectInstance mobEffectInstance : this.effects) { -- if (entity.addEffect(new MobEffectInstance(mobEffectInstance))) { -+ if (entity.addEffect(new MobEffectInstance(mobEffectInstance), cause)) { // CraftBukkit - flag = true; + for (MobEffectInstance effect : this.effects) { +- if (user.addEffect(new MobEffectInstance(effect))) { ++ if (user.addEffect(new MobEffectInstance(effect), cause)) { // CraftBukkit + anyApplied = true; } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch index 37064488ba3e..5cec4d4735c9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch @@ -4,11 +4,11 @@ } @Override -- public boolean apply(Level level, ItemStack stack, LivingEntity entity) { -- return entity.removeAllEffects(); +- public boolean apply(final Level level, final ItemStack stack, final LivingEntity user) { +- return user.removeAllEffects(); + // CraftBukkit start -+ public boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { -+ return entity.removeAllEffects(cause); ++ public boolean apply(final Level level, final ItemStack stack, final LivingEntity user, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { ++ return user.removeAllEffects(cause); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch index af59bc597a87..95ff41a54c96 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch @@ -4,14 +4,14 @@ ConsumeEffect.Type getType(); -- boolean apply(Level level, ItemStack stack, LivingEntity entity); +- boolean apply(final Level level, final ItemStack stack, final LivingEntity user); + // CraftBukkit start -+ default boolean apply(Level level, ItemStack stack, LivingEntity entity) { -+ return this.apply(level, stack, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); ++ default boolean apply(final Level level, final ItemStack stack, final LivingEntity user) { ++ return this.apply(level, stack, user, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN); + } + -+ default boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { -+ return this.apply(level, stack, entity); ++ default boolean apply(Level level, ItemStack stack, LivingEntity user, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { ++ return this.apply(level, stack, user); + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java.patch index 9cd988de2380..90f417806e9e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java +++ b/net/minecraft/world/item/consume_effects/RemoveStatusEffectsConsumeEffect.java -@@ -35,11 +_,11 @@ +@@ -33,11 +_,11 @@ } @Override -- public boolean apply(Level level, ItemStack stack, LivingEntity entity) { -+ public boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { // CraftBukkit - boolean flag = false; +- public boolean apply(final Level level, final ItemStack stack, final LivingEntity user) { ++ public boolean apply(final Level level, final ItemStack stack, final LivingEntity user, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { // CraftBukkit + boolean hasRemovedAny = false; - for (Holder holder : this.effects) { -- if (entity.removeEffect(holder)) { -+ if (entity.removeEffect(holder, cause)) { // CraftBukkit - flag = true; + for (Holder effect : this.effects) { +- if (user.removeEffect(effect)) { ++ if (user.removeEffect(effect, cause)) { // CraftBukkit + hasRemovedAny = true; } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java.patch index 9731540c3630..8e058ad573f6 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java +++ b/net/minecraft/world/item/consume_effects/TeleportRandomlyConsumeEffect.java -@@ -55,7 +_,13 @@ +@@ -54,7 +_,13 @@ } - Vec3 vec3 = entity.position(); -- if (entity.randomTeleport(d, d1, d2, true)) { + Vec3 oldPos = user.position(); +- if (user.randomTeleport(xx, yy, zz, true)) { + // CraftBukkit start - handle canceled status of teleport event -+ java.util.Optional status = entity.randomTeleport(d, d1, d2, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CONSUMABLE_EFFECT); ++ java.util.Optional status = user.randomTeleport(xx, yy, zz, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CONSUMABLE_EFFECT); + + // teleport event was canceled, no more tries + if (status.isEmpty()) break; + if (status.get()) { + // CraftBukkit end - level.gameEvent(GameEvent.TELEPORT, vec3, GameEvent.Context.of(entity)); + level.gameEvent(GameEvent.TELEPORT, oldPos, GameEvent.Context.of(user)); SoundSource soundSource; SoundEvent soundEvent; diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/BlastingRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/BlastingRecipe.java.patch index 320c3c5413b0..02e1ed2ad5bb 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/BlastingRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/BlastingRecipe.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/crafting/BlastingRecipe.java +++ b/net/minecraft/world/item/crafting/BlastingRecipe.java -@@ -31,4 +_,17 @@ +@@ -45,4 +_,17 @@ case FOOD, MISC -> RecipeBookCategories.BLAST_FURNACE_MISC; }; } @@ -8,7 +8,7 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result().create()); + + org.bukkit.craftbukkit.inventory.CraftBlastingRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftBlastingRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime()); + recipe.setGroup(this.group()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch index 876f5b6f1dc9..d4c7ada5ca9e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/crafting/CampfireCookingRecipe.java +++ b/net/minecraft/world/item/crafting/CampfireCookingRecipe.java -@@ -28,4 +_,17 @@ +@@ -42,4 +_,17 @@ public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.CAMPFIRE; } @@ -8,7 +8,7 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result().create()); + + org.bukkit.craftbukkit.inventory.CraftCampfireRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftCampfireRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime()); + recipe.setGroup(this.group()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/CustomRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/CustomRecipe.java.patch index bbf2d6450637..c1039cdf82a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/CustomRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/CustomRecipe.java.patch @@ -1,22 +1,18 @@ --- a/net/minecraft/world/item/crafting/CustomRecipe.java +++ b/net/minecraft/world/item/crafting/CustomRecipe.java -@@ -30,6 +_,19 @@ +@@ -28,4 +_,15 @@ + @Override public abstract RecipeSerializer getSerializer(); - ++ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.EMPTY); -+ -+ org.bukkit.craftbukkit.inventory.CraftComplexRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, result, this); ++ org.bukkit.craftbukkit.inventory.CraftComplexRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, org.bukkit.inventory.ItemStack.empty(), this); + recipe.setGroup(this.group()); + recipe.setCategory(org.bukkit.craftbukkit.inventory.CraftRecipe.getCategory(this.category())); + + return recipe; + } + // CraftBukkit end -+ - public static class Serializer implements RecipeSerializer { - private final MapCodec codec; - private final StreamCodec streamCodec; + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/DyeRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/DyeRecipe.java.patch new file mode 100644 index 000000000000..71a1c0cb5c80 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/DyeRecipe.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/item/crafting/DyeRecipe.java ++++ b/net/minecraft/world/item/crafting/DyeRecipe.java +@@ -148,4 +_,15 @@ + ) + ); + } ++ ++ // CraftBukkit start ++ @Override ++ public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result.create()); ++ org.bukkit.craftbukkit.inventory.CraftComplexRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, result, this); ++ recipe.setGroup(this.group()); ++ recipe.setCategory(org.bukkit.craftbukkit.inventory.CraftRecipe.getCategory(this.category())); ++ return recipe; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/ImbueRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/ImbueRecipe.java.patch new file mode 100644 index 000000000000..5ee63591cb3d --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/ImbueRecipe.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/item/crafting/ImbueRecipe.java ++++ b/net/minecraft/world/item/crafting/ImbueRecipe.java +@@ -113,4 +_,15 @@ + ) + ); + } ++ ++ // CraftBukkit start ++ @Override ++ public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result.create()); ++ org.bukkit.craftbukkit.inventory.CraftComplexRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, result, this); ++ recipe.setGroup(this.group()); ++ recipe.setCategory(org.bukkit.craftbukkit.inventory.CraftRecipe.getCategory(this.category())); ++ return recipe; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch index 28c29f80e678..8a3b5763deb5 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch @@ -1,19 +1,17 @@ --- a/net/minecraft/world/item/crafting/Ingredient.java +++ b/net/minecraft/world/item/crafting/Ingredient.java -@@ -33,6 +_,25 @@ - public static final Codec CODEC = ExtraCodecs.nonEmptyHolderSet(NON_AIR_HOLDER_SET_CODEC) - .xmap(Ingredient::new, ingredient -> ingredient.values); +@@ -33,6 +_,23 @@ + public static final Codec> NON_AIR_HOLDER_SET_CODEC = HolderSetCodec.create(Registries.ITEM, Item.CODEC, false); + public static final Codec CODEC = ExtraCodecs.nonEmptyHolderSet(NON_AIR_HOLDER_SET_CODEC).xmap(Ingredient::new, i -> i.values); public final HolderSet values; + // CraftBukkit start -+ @javax.annotation.Nullable -+ private java.util.List itemStacks; ++ private java.util.@org.jspecify.annotations.Nullable List itemStacks; + + public boolean isExact() { + return this.itemStacks != null; + } + -+ @javax.annotation.Nullable -+ public java.util.List itemStacks() { ++ public java.util.@org.jspecify.annotations.Nullable List itemStacks() { + return this.itemStacks; + } + @@ -24,16 +22,16 @@ + } + // CraftBukkit end - private Ingredient(HolderSet values) { - values.unwrap().ifRight(list -> { + private Ingredient(final HolderSet values) { + values.unwrap().ifRight(directValues -> { @@ -60,6 +_,17 @@ @Override - public boolean test(ItemStack stack) { + public boolean test(final ItemStack input) { + // CraftBukkit start + if (this.isExact()) { + for (ItemStack itemstack1 : this.itemStacks()) { -+ if (itemstack1.getItem() == stack.getItem() && ItemStack.isSameItemSameComponents(stack, itemstack1)) { ++ if (itemstack1.getItem() == input.getItem() && ItemStack.isSameItemSameComponents(input, itemstack1)) { + return true; + } + } @@ -41,15 +39,15 @@ + return false; + } + // CraftBukkit end - return stack.is(this.values); + return input.is(this.values); } @@ -70,7 +_,7 @@ @Override - public boolean equals(Object other) { -- return other instanceof Ingredient ingredient && Objects.equals(this.values, ingredient.values); -+ return other instanceof Ingredient ingredient && Objects.equals(this.values, ingredient.values) && Objects.equals(this.itemStacks, ingredient.itemStacks); // CraftBukkit + public boolean equals(final Object o) { +- return o instanceof Ingredient other && Objects.equals(this.values, other.values); ++ return o instanceof Ingredient other && Objects.equals(this.values, other.values) && Objects.equals(this.itemStacks, other.itemStacks); // CraftBukkit } - public static Ingredient of(ItemLike item) { + public static Ingredient of(final ItemLike itemLike) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/Recipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/Recipe.java.patch index 9bad69b28f0e..e125c6cda4cf 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/Recipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/Recipe.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/item/crafting/Recipe.java +++ b/net/minecraft/world/item/crafting/Recipe.java -@@ -46,4 +_,6 @@ +@@ -82,4 +_,6 @@ + ByteBufCodecs.BOOL, Recipe.CommonInfo::showNotification, Recipe.CommonInfo::new + ); } - - RecipeBookCategory recipeBookCategory(); + + org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeHolder.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeHolder.java.patch index a62881aad338..f8c5a7bc4014 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeHolder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeHolder.java.patch @@ -11,5 +11,5 @@ + // CraftBukkit end + @Override - public boolean equals(Object other) { - return this == other || other instanceof RecipeHolder recipeHolder && this.id == recipeHolder.id; + public boolean equals(final Object obj) { + return this == obj || obj instanceof RecipeHolder holder && this.id == holder.id; diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch index 31ec46f411c1..a1af6d5311a2 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/item/crafting/RecipeManager.java +++ b/net/minecraft/world/item/crafting/RecipeManager.java @@ -87,7 +_,26 @@ - LOGGER.info("Loaded {} recipes", object.values().size()); + LOGGER.info("Loaded {} recipes", recipes.values().size()); } + // CraftBukkit start @@ -21,27 +21,27 @@ + } + } + - public void finalizeRecipeLoading(FeatureFlagSet enabledFeatures) { -+ this.featureflagset = enabledFeatures; + public void finalizeRecipeLoading(final FeatureFlagSet enabledFlags) { ++ this.featureflagset = enabledFlags; + // CraftBukkit end - List> list = new ArrayList<>(); - List list1 = RECIPE_PROPERTY_SETS.entrySet() + List> stonecutterRecipes = new ArrayList<>(); + List propertySetCollectors = RECIPE_PROPERTY_SETS.entrySet() .stream() -@@ -147,7 +_,10 @@ +@@ -144,7 +_,10 @@ } - public > Optional> getRecipeFor(RecipeType recipeType, I input, Level level) { -- return this.recipes.getRecipesFor(recipeType, input, level).findFirst(); + public > Optional> getRecipeFor(final RecipeType type, final I input, final Level level) { +- return this.recipes.getRecipesFor(type, input, level).findFirst(); + // CraftBukkit start -+ List> list = this.recipes.getRecipesFor(recipeType, input, level).toList(); ++ List> list = this.recipes.getRecipesFor(type, input, level).toList(); + return (list.isEmpty()) ? Optional.empty() : Optional.of(list.getLast()); // CraftBukkit - SPIGOT-4638: last recipe gets priority + // CraftBukkit end } - public Optional> byKey(ResourceKey> key) { -@@ -198,6 +_,22 @@ - Recipe recipe1 = Recipe.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json).getOrThrow(JsonParseException::new); - return new RecipeHolder<>(recipe, recipe1); + public Optional> byKey(final ResourceKey> recipeId) { +@@ -195,6 +_,22 @@ + Recipe recipe = Recipe.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), object).getOrThrow(JsonParseException::new); + return new RecipeHolder<>(id, recipe); } + + // CraftBukkit start @@ -60,5 +60,5 @@ + } + // CraftBukkit end - public static > RecipeManager.CachedCheck createCheck(final RecipeType recipeType) { + public static > RecipeManager.CachedCheck createCheck(final RecipeType type) { return new RecipeManager.CachedCheck() { diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeMap.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeMap.java.patch index b5b71509f500..0d75fa26286e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeMap.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeMap.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/item/crafting/RecipeMap.java +++ b/net/minecraft/world/item/crafting/RecipeMap.java @@ -30,8 +_,34 @@ - builder1.put(recipeHolder.id(), recipeHolder); + byKey.put(recipe.id(), recipe); } -- return new RecipeMap(builder.build(), builder1.build()); +- return new RecipeMap(byType.build(), byKey.build()); - } + // CraftBukkit start - mutable -+ return new RecipeMap(com.google.common.collect.LinkedHashMultimap.create(builder.build()), com.google.common.collect.Maps.newLinkedHashMap(builder1.build())); ++ return new RecipeMap(com.google.common.collect.LinkedHashMultimap.create(byType.build()), com.google.common.collect.Maps.newLinkedHashMap(byKey.build())); + } + + public void addRecipe(RecipeHolder holder) { @@ -35,5 +35,5 @@ + } + // Paper end - replace removeRecipe implementation - public > Collection> byType(RecipeType type) { + public > Collection> byType(final RecipeType type) { return (Collection)this.byType.get(type); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapedRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapedRecipe.java.patch index 075f7f7cf2af..a3f66dff59bb 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapedRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapedRecipe.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/item/crafting/ShapedRecipe.java +++ b/net/minecraft/world/item/crafting/ShapedRecipe.java -@@ -102,6 +_,68 @@ +@@ -93,4 +_,65 @@ + ) ); } - + // CraftBukkit start + @Override + public org.bukkit.inventory.ShapedRecipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result.create()); + org.bukkit.craftbukkit.inventory.CraftShapedRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftShapedRecipe(id, result, this); -+ recipe.setGroup(this.group); ++ recipe.setGroup(this.group()); + recipe.setCategory(org.bukkit.craftbukkit.inventory.CraftRecipe.getCategory(this.category())); + + switch (this.pattern.height()) { @@ -65,7 +65,4 @@ + return recipe; + } + // CraftBukkit end -+ - public static class Serializer implements RecipeSerializer { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch index be840f254289..9453d2c1b6ec 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/item/crafting/ShapelessRecipe.java +++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java -@@ -30,6 +_,21 @@ +@@ -47,6 +_,21 @@ this.ingredients = ingredients; } + // CraftBukkit start + @Override + public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result.create()); + org.bukkit.craftbukkit.inventory.CraftShapelessRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftShapelessRecipe(id, result, this); -+ recipe.setGroup(this.group); ++ recipe.setGroup(this.group()); + recipe.setCategory(org.bukkit.craftbukkit.inventory.CraftRecipe.getCategory(this.category())); + + for (Ingredient list : this.ingredients) { @@ -21,4 +21,4 @@ + @Override public RecipeSerializer getSerializer() { - return RecipeSerializer.SHAPELESS_RECIPE; + return SERIALIZER; diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch index c174cfdcf8b9..3e484fe27656 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/crafting/SmeltingRecipe.java +++ b/net/minecraft/world/item/crafting/SmeltingRecipe.java -@@ -32,4 +_,17 @@ +@@ -46,4 +_,17 @@ case MISC -> RecipeBookCategories.FURNACE_MISC; }; } @@ -8,7 +8,7 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result().create()); + + org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime()); + recipe.setGroup(this.group()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch index 4058cfeaa29d..94cc51346265 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch @@ -1,31 +1,45 @@ --- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java +++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java -@@ -20,8 +_,15 @@ - final Optional addition; - final TransmuteResult result; - private @Nullable PlacementInfo placementInfo; -+ final boolean copyDataComponents; // Paper - Option to prevent data components copy +@@ -42,6 +_,7 @@ + private final Ingredient base; + private final Optional addition; + private final ItemStackTemplate result; ++ private final boolean copyDataComponents; // Paper - Option to prevent data components copy - public SmithingTransformRecipe(Optional template, Ingredient base, Optional addition, TransmuteResult result) { + public SmithingTransformRecipe( + final Recipe.CommonInfo commonInfo, +@@ -50,7 +_,21 @@ + final Optional addition, + final ItemStackTemplate result + ) { + // Paper start - Option to prevent data components copy -+ this(template, base, addition, result, true); ++ this(commonInfo, template, base, addition, result, true); + } -+ public SmithingTransformRecipe(Optional template, Ingredient base, Optional addition, TransmuteResult result, boolean copyDataComponents) { ++ ++ public SmithingTransformRecipe( ++ final Recipe.CommonInfo commonInfo, ++ final Optional template, ++ final Ingredient base, ++ final Optional addition, ++ final ItemStackTemplate result, ++ final boolean copyDataComponents ++ ) { + super(commonInfo); + this.copyDataComponents = copyDataComponents; + // Paper end - Option to prevent data components copy this.template = template; this.base = base; this.addition = addition; -@@ -30,7 +_,7 @@ +@@ -59,7 +_,7 @@ @Override - public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { -- return this.result.apply(input.base()); -+ return this.result.apply(input.base(), this.copyDataComponents); // Paper - Option to prevent data components copy + public ItemStack assemble(final SmithingRecipeInput input) { +- return TransmuteRecipe.createWithOriginalComponents(this.result, input.base()); ++ return this.copyDataComponents ? TransmuteRecipe.createWithOriginalComponents(this.result, input.base()) : this.result.create(); // Paper - Option to prevent data components copy } @Override -@@ -74,6 +_,17 @@ +@@ -99,4 +_,15 @@ ) ); } @@ -33,13 +47,11 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(this.result.item(), this.result.count(), this.result.components())); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result.create()); + + org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.template), org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.base), org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.addition), this.copyDataComponents); // Paper - Option to prevent data components copy + + return recipe; + } + // CraftBukkit end - - public static class Serializer implements RecipeSerializer { - private static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch index b71e1693cffa..9bce6ec5c470 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch @@ -1,58 +1,60 @@ --- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java +++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java -@@ -27,8 +_,15 @@ - final Ingredient addition; - final Holder pattern; - private @Nullable PlacementInfo placementInfo; +@@ -47,11 +_,20 @@ + private final Ingredient base; + private final Ingredient addition; + private final Holder pattern; + final boolean copyDataComponents; // Paper - Option to prevent data components copy - public SmithingTrimRecipe(Ingredient template, Ingredient base, Ingredient addition, Holder pattern) { + public SmithingTrimRecipe( + final Recipe.CommonInfo commonInfo, final Ingredient template, final Ingredient base, final Ingredient addition, final Holder pattern + ) { + // Paper start - Option to prevent data components copy -+ this(template, base, addition, pattern, true); ++ this(commonInfo, template, base, addition, pattern, true); + } -+ public SmithingTrimRecipe(Ingredient template, Ingredient base, Ingredient addition, Holder pattern, final boolean copyDataComponents) { -+ this.copyDataComponents = copyDataComponents; ++ public SmithingTrimRecipe( ++ final Recipe.CommonInfo commonInfo, final Ingredient template, final Ingredient base, final Ingredient addition, final Holder pattern, final boolean copyDataComponents ++ ) { + // Paper end - Option to prevent data components copy + super(commonInfo); ++ this.copyDataComponents = copyDataComponents; // Paper this.template = template; this.base = base; this.addition = addition; -@@ -37,10 +_,15 @@ +@@ -60,10 +_,15 @@ @Override - public ItemStack assemble(SmithingRecipeInput input, HolderLookup.Provider registries) { -- return applyTrim(registries, input.base(), input.addition(), this.pattern); -+ return applyTrim(registries, input.base(), input.addition(), this.pattern, this.copyDataComponents); // Paper start - Option to prevent data components copy + public ItemStack assemble(final SmithingRecipeInput input) { +- return applyTrim(input.base(), input.addition(), this.pattern); ++ return applyTrim(input.base(), input.addition(), this.pattern, this.copyDataComponents); // Paper start - Option to prevent data components copy } - public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, Holder pattern) { -+ // Paper start - Option to prevent data components copy -+ return applyTrim(registries, base, addition, pattern, true); + public static ItemStack applyTrim(final ItemStack baseItem, final ItemStack materialItem, final Holder pattern) { ++ // Paper start - Option to prevent data components copy ++ return applyTrim(baseItem, materialItem, pattern, true); + } -+ public static ItemStack applyTrim(HolderLookup.Provider registries, ItemStack base, ItemStack addition, Holder pattern, final boolean copyDataComponents) { -+ // Paper end - Option to prevent data components copy - Optional> fromIngredient = TrimMaterials.getFromIngredient(registries, addition); - if (fromIngredient.isPresent()) { - ArmorTrim armorTrim = base.get(DataComponents.TRIM); -@@ -48,7 +_,7 @@ - if (Objects.equals(armorTrim, armorTrim1)) { ++ public static ItemStack applyTrim(final ItemStack baseItem, final ItemStack materialItem, final Holder pattern, final boolean copyDataComponents) { ++ // Paper end - Option to prevent data components copy + Holder material = materialItem.get(DataComponents.PROVIDES_TRIM_MATERIAL); + if (material != null) { + ArmorTrim existingTrim = baseItem.get(DataComponents.TRIM); +@@ -71,7 +_,7 @@ + if (Objects.equals(existingTrim, newTrim)) { return ItemStack.EMPTY; } else { -- ItemStack itemStack = base.copyWithCount(1); -+ ItemStack itemStack = copyDataComponents ? base.copyWithCount(1) : new ItemStack(base.getItem(), 1); // Paper - Option to prevent data components copy - itemStack.set(DataComponents.TRIM, armorTrim1); - return itemStack; +- ItemStack trimmedItem = baseItem.copyWithCount(1); ++ ItemStack trimmedItem = copyDataComponents ? baseItem.copyWithCount(1) : new ItemStack(baseItem.getItem(), 1); // Paper - Option to prevent data components copy + trimmedItem.set(DataComponents.TRIM, newTrim); + return trimmedItem; } -@@ -101,6 +_,13 @@ +@@ -120,4 +_,10 @@ ) ); } -+ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { + return new org.bukkit.craftbukkit.inventory.CraftSmithingTrimRecipe(id, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.template), org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.base), org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.addition), org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern.minecraftHolderToBukkit(this.pattern), this.copyDataComponents); // Paper - Option to prevent data components copy + } + // CraftBukkit end - - public static class Serializer implements RecipeSerializer { - private static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmokingRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmokingRecipe.java.patch index e952bdf1b630..9d3ee976db81 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmokingRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmokingRecipe.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/crafting/SmokingRecipe.java +++ b/net/minecraft/world/item/crafting/SmokingRecipe.java -@@ -28,4 +_,17 @@ +@@ -42,4 +_,17 @@ public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.SMOKER_FOOD; } @@ -8,7 +8,7 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result().create()); + + org.bukkit.craftbukkit.inventory.CraftSmokingRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftSmokingRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.input()), this.experience(), this.cookingTime()); + recipe.setGroup(this.group()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch index daa51ba292ed..5e83c38b7d49 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/crafting/StonecutterRecipe.java +++ b/net/minecraft/world/item/crafting/StonecutterRecipe.java -@@ -35,4 +_,16 @@ +@@ -47,4 +_,16 @@ public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.STONECUTTER; } @@ -8,7 +8,7 @@ + // CraftBukkit start + @Override + public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this.result().create()); + + org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe recipe = new org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe(id, result, org.bukkit.craftbukkit.inventory.CraftRecipe.toBukkit(this.input())); + recipe.setGroup(this.group()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteRecipe.java.patch index 742d7149df35..33e826780b77 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteRecipe.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/item/crafting/TransmuteRecipe.java +++ b/net/minecraft/world/item/crafting/TransmuteRecipe.java -@@ -84,6 +_,13 @@ - ); +@@ -201,6 +_,13 @@ + return this.materialCount.max().orElse(8); } + // CraftBukkit start @@ -13,4 +13,4 @@ + @Override public RecipeSerializer getSerializer() { - return RecipeSerializer.TRANSMUTE; + return SERIALIZER; diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteResult.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteResult.java.patch deleted file mode 100644 index e261851208fc..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/TransmuteResult.java.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/net/minecraft/world/item/crafting/TransmuteResult.java -+++ b/net/minecraft/world/item/crafting/TransmuteResult.java -@@ -45,8 +_,13 @@ - } - - public ItemStack apply(ItemStack stack) { -+ // Paper start - Option to prevent data components copy -+ return apply(stack, true); -+ } -+ public ItemStack apply(ItemStack stack, boolean applyComponents) { -+ // Paper end - Option to prevent data components copy - ItemStack itemStack = stack.transmuteCopy(this.item.value(), this.count); -- itemStack.applyComponents(this.components); -+ if (applyComponents) itemStack.applyComponents(this.components); // Paper - Option to prevent data components copy - return itemStack; - } - diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch index beb8db3ee9fc..710eb1e8c82e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java +++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java -@@ -52,8 +_,14 @@ +@@ -53,8 +_,14 @@ } - public static ItemEnchantments updateEnchantments(ItemStack stack, Consumer updater) { + public static ItemEnchantments updateEnchantments(final ItemStack itemStack, final Consumer consumer) { + // Paper start - allowing updating enchantments on items without component -+ return updateEnchantments(stack, updater, false); ++ return updateEnchantments(itemStack, consumer, false); + } + -+ public static ItemEnchantments updateEnchantments(ItemStack stack, Consumer updater, final boolean createComponentIfMissing) { ++ public static ItemEnchantments updateEnchantments(final ItemStack itemStack, final Consumer consumer, final boolean createComponentIfMissing) { + // Paper end - allowing updating enchantments on items without component - DataComponentType componentType = getComponentType(stack); -- ItemEnchantments itemEnchantments = stack.get(componentType); -+ ItemEnchantments itemEnchantments = createComponentIfMissing ? stack.getOrDefault(componentType, ItemEnchantments.EMPTY) : stack.get(componentType); // Paper - allowing updating enchantments on items without component - if (itemEnchantments == null) { + DataComponentType componentType = getComponentType(itemStack); +- ItemEnchantments oldEnchantments = itemStack.get(componentType); ++ ItemEnchantments oldEnchantments = createComponentIfMissing ? itemStack.getOrDefault(componentType, ItemEnchantments.EMPTY) : itemStack.get(componentType); // Paper - allowing updating enchantments on items without component + if (oldEnchantments == null) { return ItemEnchantments.EMPTY; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch index 69112ac4b10c..d09e74863916 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/enchantment/ItemEnchantments.java +++ b/net/minecraft/world/item/enchantment/ItemEnchantments.java -@@ -28,21 +_,24 @@ +@@ -28,19 +_,22 @@ import org.jspecify.annotations.Nullable; public class ItemEnchantments implements TooltipProvider { @@ -14,28 +14,26 @@ .xmap( - map -> new ItemEnchantments(new Object2IntOpenHashMap<>((Map, ? extends Integer>)map)), + map -> new net.minecraft.world.item.enchantment.ItemEnchantments(net.minecraft.util.Util.make(new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), m -> m.putAll(map))), // Paper - sort enchantments - itemEnchantments -> itemEnchantments.enchantments + enchantments -> enchantments.enchantments ); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( -- ByteBufCodecs.map(Object2IntOpenHashMap::new, Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT), -+ ByteBufCodecs.map((v) -> new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT), // Paper - itemEnchantments -> itemEnchantments.enchantments, - ItemEnchantments::new +- ByteBufCodecs.map(Object2IntOpenHashMap::new, Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT), c -> c.enchantments, ItemEnchantments::new ++ ByteBufCodecs.map((v) -> new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), Enchantment.STREAM_CODEC, ByteBufCodecs.VAR_INT), c -> c.enchantments, ItemEnchantments::new // Paper ); -- final Object2IntOpenHashMap> enchantments; -+ final it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap> enchantments; // Paper +- private final Object2IntOpenHashMap> enchantments; ++ private final it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap> enchantments; // Paper -- ItemEnchantments(Object2IntOpenHashMap> enchantments) { -+ ItemEnchantments(it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap> enchantments) { // Paper +- private ItemEnchantments(final Object2IntOpenHashMap> enchantments) { ++ private ItemEnchantments(final it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap> enchantments) { // Paper this.enchantments = enchantments; for (Entry> entry : enchantments.object2IntEntrySet()) { -@@ -120,7 +_,7 @@ +@@ -122,7 +_,7 @@ } public static class Mutable { - private final Object2IntOpenHashMap> enchantments = new Object2IntOpenHashMap<>(); + private final it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap> enchantments = new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER); // Paper - public Mutable(ItemEnchantments enchantments) { + public Mutable(final ItemEnchantments enchantments) { this.enchantments.putAll(enchantments.enchantments); diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyExhaustion.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyExhaustion.java.patch index 6c7e2f12762e..097c4e81a4c9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyExhaustion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyExhaustion.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/item/enchantment/effects/ApplyExhaustion.java @@ -17,7 +_,7 @@ @Override - public void apply(ServerLevel level, int enchantmentLevel, EnchantedItemInUse item, Entity entity, Vec3 origin) { - if (entity instanceof Player player) { -- player.causeFoodExhaustion(this.amount.calculate(enchantmentLevel)); -+ player.causeFoodExhaustion(this.amount.calculate(enchantmentLevel), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ENCHANTMENT_EFFECT); // Paper - add ExhaustionReason + public void apply(final ServerLevel serverLevel, final int enchantmentLevel, final EnchantedItemInUse item, final Entity entity, final Vec3 position) { + if (entity instanceof Player livingEntity) { +- livingEntity.causeFoodExhaustion(this.amount.calculate(enchantmentLevel)); ++ livingEntity.causeFoodExhaustion(this.amount.calculate(enchantmentLevel), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ENCHANTMENT_EFFECT); // Paper - add ExhaustionReason } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java.patch index 47f39569b25f..1fb618eacb35 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java +++ b/net/minecraft/world/item/enchantment/effects/ApplyMobEffect.java @@ -44,7 +_,7 @@ - int max = Math.max( + int amplifier = Math.max( 0, Math.round(Mth.randomBetween(random, this.minAmplifier.calculate(enchantmentLevel), this.maxAmplifier.calculate(enchantmentLevel))) ); -- livingEntity.addEffect(new MobEffectInstance(randomElement.get(), rounded, max)); -+ livingEntity.addEffect(new MobEffectInstance(randomElement.get(), rounded, max), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit +- living.addEffect(new MobEffectInstance(selected.get(), ticks, amplifier)); ++ living.addEffect(new MobEffectInstance(selected.get(), ticks, amplifier), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java.patch index 0de21ed24c3b..f5077c7f54f7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java +++ b/net/minecraft/world/item/enchantment/effects/ChangeItemDamage.java -@@ -21,9 +_,9 @@ - public void apply(ServerLevel level, int enchantmentLevel, EnchantedItemInUse item, Entity entity, Vec3 origin) { +@@ -20,9 +_,9 @@ + public void apply(final ServerLevel serverLevel, final int enchantmentLevel, final EnchantedItemInUse item, final Entity entity, final Vec3 position) { ItemStack itemStack = item.itemStack(); if (itemStack.has(DataComponents.MAX_DAMAGE) && itemStack.has(DataComponents.DAMAGE)) { -- ServerPlayer serverPlayer1 = item.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; -+ //ServerPlayer serverPlayer1 = item.owner() instanceof ServerPlayer serverPlayer ? serverPlayer : null; // Paper - EntityDamageItemEvent - always pass in entity - int i = (int)this.amount.calculate(enchantmentLevel); -- itemStack.hurtAndBreak(i, level, serverPlayer1, item.onBreak()); -+ itemStack.hurtAndBreak(i, level, item.owner(), item.onBreak()); // Paper - EntityDamageItemEvent - always pass in entity +- ServerPlayer player = item.owner() instanceof ServerPlayer sp ? sp : null; ++ //ServerPlayer player = item.owner() instanceof ServerPlayer sp ? sp : null; // Paper - EntityDamageItemEvent - always pass in entity + int change = (int)this.amount.calculate(enchantmentLevel); +- itemStack.hurtAndBreak(change, serverLevel, player, item.onBreak()); ++ itemStack.hurtAndBreak(change, serverLevel, item.owner(), item.onBreak()); // Paper - EntityDamageItemEvent - always pass in entity } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/Ignite.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/Ignite.java.patch index e1daa636a564..43008d9c39d1 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/Ignite.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/Ignite.java.patch @@ -3,7 +3,7 @@ @@ -15,7 +_,21 @@ @Override - public void apply(ServerLevel level, int enchantmentLevel, EnchantedItemInUse item, Entity entity, Vec3 origin) { + public void apply(final ServerLevel serverLevel, final int enchantmentLevel, final EnchantedItemInUse item, final Entity entity, final Vec3 position) { - entity.igniteForSeconds(this.duration.calculate(enchantmentLevel)); + // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item + org.bukkit.event.entity.EntityCombustEvent entityCombustEvent; diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java.patch index a6bbec7a4699..a963dc2f4136 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java +++ b/net/minecraft/world/item/enchantment/effects/ReplaceBlock.java @@ -30,7 +_,7 @@ - public void apply(ServerLevel level, int enchantmentLevel, EnchantedItemInUse item, Entity entity, Vec3 origin) { - BlockPos blockPos = BlockPos.containing(origin).offset(this.offset); - if (this.predicate.map(blockPredicate -> blockPredicate.test(level, blockPos)).orElse(true) -- && level.setBlockAndUpdate(blockPos, this.blockState.getState(entity.getRandom(), blockPos))) { -+ && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, blockPos, this.blockState.getState(entity.getRandom(), blockPos), net.minecraft.world.level.block.Block.UPDATE_ALL, entity, true)) { // CraftBukkit - Call EntityBlockFormEvent - this.triggerGameEvent.ifPresent(holder -> level.gameEvent(entity, (Holder)holder, blockPos)); + public void apply(final ServerLevel serverLevel, final int enchantmentLevel, final EnchantedItemInUse item, final Entity entity, final Vec3 position) { + BlockPos pos = BlockPos.containing(position).offset(this.offset); + if (this.predicate.map(p -> p.test(serverLevel, pos)).orElse(true) +- && serverLevel.setBlockAndUpdate(pos, this.blockState.getState(serverLevel, entity.getRandom(), pos))) { ++ && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(serverLevel, pos, this.blockState.getState(serverLevel, entity.getRandom(), pos), net.minecraft.world.level.block.Block.UPDATE_ALL, entity, true)) { // CraftBukkit - Call EntityBlockFormEvent + this.triggerGameEvent.ifPresent(event -> serverLevel.gameEvent(entity, (Holder)event, pos)); } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java.patch index 595c641c4775..344581b6bf95 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java +++ b/net/minecraft/world/item/enchantment/effects/ReplaceDisk.java @@ -47,7 +_,7 @@ - for (BlockPos blockPos1 : BlockPos.betweenClosed(blockPos.offset(-i, 0, -i), blockPos.offset(i, Math.min(i1 - 1, 0), i))) { - if (blockPos1.distToCenterSqr(origin.x(), blockPos1.getY() + 0.5, origin.z()) < Mth.square(i) - && this.predicate.map(predicate -> predicate.test(level, blockPos1)).orElse(true) -- && level.setBlockAndUpdate(blockPos1, this.blockState.getState(random, blockPos1))) { -+ && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, blockPos1, this.blockState.getState(random, blockPos1), net.minecraft.world.level.block.Block.UPDATE_ALL, entity, true)) { // CraftBukkit - Call EntityBlockFormEvent for Frost Walker - this.triggerGameEvent.ifPresent(event -> level.gameEvent(entity, (Holder)event, blockPos1)); + for (BlockPos pos : BlockPos.betweenClosed(centerBlock.offset(-dist, 0, -dist), centerBlock.offset(dist, Math.min(height - 1, 0), dist))) { + if (pos.distToCenterSqr(position.x(), pos.getY() + 0.5, position.z()) < Mth.square(dist) + && this.predicate.map(p -> p.test(serverLevel, pos)).orElse(true) +- && serverLevel.setBlockAndUpdate(pos, this.blockState.getState(serverLevel, random, pos))) { ++ && org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(serverLevel, pos, this.blockState.getState(serverLevel, random, pos), net.minecraft.world.level.block.Block.UPDATE_ALL, entity, true)) { // CraftBukkit - Call EntityBlockFormEvent for Frost Walker + this.triggerGameEvent.ifPresent(event -> serverLevel.gameEvent(entity, (Holder)event, pos)); } } diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java.patch index 68a887a1c965..560a2910998d 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java +++ b/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java -@@ -58,8 +_,13 @@ - Vec3 knownMovement = entity.getKnownMovement(); +@@ -59,8 +_,13 @@ + Vec3 movement = entity.getKnownMovement(); float bbWidth = entity.getBbWidth(); float bbHeight = entity.getBbHeight(); -- level.sendParticles( +- serverLevel.sendParticles( + // Paper start - Hide soul speed particles for vanished players -+ level.sendParticlesSource( ++ serverLevel.sendParticlesSource( + entity, this.particle, + false, + false, -+ // Paper end - Hide soul speed particles for vanished players - this.horizontalPosition.getCoordinate(origin.x(), origin.x(), bbWidth, random), - this.verticalPosition.getCoordinate(origin.y(), origin.y() + bbHeight / 2.0F, bbHeight, random), - this.horizontalPosition.getCoordinate(origin.z(), origin.z(), bbWidth, random), ++ // Paper end - Hide soul speed particles for vanished players + this.horizontalPosition.getCoordinate(position.x(), position.x(), bbWidth, random), + this.verticalPosition.getCoordinate(position.y(), position.y() + bbHeight / 2.0F, bbHeight, random), + this.horizontalPosition.getCoordinate(position.z(), position.z(), bbWidth, random), diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java.patch index cf03e4582d65..6a4eaf8128a1 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java.patch @@ -2,21 +2,21 @@ +++ b/net/minecraft/world/item/enchantment/effects/SummonEntityEffect.java @@ -34,11 +_,18 @@ if (Level.isInSpawnableBounds(blockPos)) { - Optional>> randomElement = this.entityTypes().getRandomElement(level.getRandom()); - if (!randomElement.isEmpty()) { -- Entity entity1 = randomElement.get().value().spawn(level, blockPos, EntitySpawnReason.TRIGGERED); -+ Entity entity1 = randomElement.get().value().create(level, null, blockPos, EntitySpawnReason.TRIGGERED, false, false); // CraftBukkit - if (entity1 != null) { - if (entity1 instanceof LightningBolt lightningBolt && item.owner() instanceof ServerPlayer serverPlayer) { - lightningBolt.setCause(serverPlayer); + Optional>> entityType = this.entityTypes().getRandomElement(serverLevel.getRandom()); + if (!entityType.isEmpty()) { +- Entity spawned = entityType.get().value().spawn(serverLevel, blockPos, EntitySpawnReason.TRIGGERED); ++ Entity spawned = entityType.get().value().create(serverLevel, null, blockPos, EntitySpawnReason.TRIGGERED, false, false); // CraftBukkit + if (spawned != null) { + if (spawned instanceof LightningBolt lightningBolt && item.owner() instanceof ServerPlayer player) { + lightningBolt.setCause(player); } + // CraftBukkit start -+ if (entity1 instanceof LightningBolt) { -+ level.strikeLightning(entity1, (item.itemStack().is(net.minecraft.world.item.Items.TRIDENT)) ? org.bukkit.event.weather.LightningStrikeEvent.Cause.TRIDENT : org.bukkit.event.weather.LightningStrikeEvent.Cause.ENCHANTMENT); ++ if (spawned instanceof LightningBolt) { ++ serverLevel.strikeLightning(spawned, (item.itemStack().is(net.minecraft.world.item.Items.TRIDENT)) ? org.bukkit.event.weather.LightningStrikeEvent.Cause.TRIDENT : org.bukkit.event.weather.LightningStrikeEvent.Cause.ENCHANTMENT); + } else { -+ level.addFreshEntityWithPassengers(entity1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENCHANTMENT); ++ serverLevel.addFreshEntityWithPassengers(spawned, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENCHANTMENT); + } + // CraftBukkit end if (this.joinTeam && entity.getTeam() != null) { - level.getScoreboard().addPlayerToTeam(entity1.getScoreboardName(), entity.getTeam()); + serverLevel.getScoreboard().addPlayerToTeam(spawned.getScoreboardName(), entity.getTeam()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/trading/Merchant.java.patch b/paper-server/patches/sources/net/minecraft/world/item/trading/Merchant.java.patch index 4e3a8a135e4c..a0db2d2fab78 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/trading/Merchant.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/trading/Merchant.java.patch @@ -8,8 +8,8 @@ + void notifyTrade(MerchantOffer offer); - void notifyTradeUpdated(ItemStack stack); -@@ -49,4 +_,6 @@ + void notifyTradeUpdated(ItemStack itemStack); +@@ -47,4 +_,6 @@ boolean isClientSide(); boolean stillValid(Player player); diff --git a/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch b/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch index acf9f09b756c..f20ec063cada 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/item/trading/MerchantOffer.java +++ b/net/minecraft/world/item/trading/MerchantOffer.java @@ -21,6 +_,7 @@ - Codec.INT.lenientOptionalFieldOf("demand", 0).forGetter(merchantOffer -> merchantOffer.demand), - Codec.FLOAT.lenientOptionalFieldOf("priceMultiplier", 0.0F).forGetter(merchantOffer -> merchantOffer.priceMultiplier), - Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter(merchantOffer -> merchantOffer.xp) -+ , Codec.BOOL.lenientOptionalFieldOf("Paper.IgnoreDiscounts", false).forGetter(merchantOffer -> merchantOffer.ignoreDiscounts) // Paper + Codec.INT.lenientOptionalFieldOf("demand", 0).forGetter(o -> o.demand), + Codec.FLOAT.lenientOptionalFieldOf("priceMultiplier", 0.0F).forGetter(o -> o.priceMultiplier), + Codec.INT.lenientOptionalFieldOf("xp", 1).forGetter(o -> o.xp) ++ , Codec.BOOL.lenientOptionalFieldOf("Paper.IgnoreDiscounts", false).forGetter(offer -> offer.ignoreDiscounts) // Paper ) - .apply(instance, MerchantOffer::new) + .apply(i, MerchantOffer::new) ); @@ -37,6 +_,21 @@ public int demand; @@ -15,7 +15,7 @@ + public boolean ignoreDiscounts; // Paper - Add ignore discounts API + + // CraftBukkit start -+ private @javax.annotation.Nullable org.bukkit.craftbukkit.inventory.CraftMerchantRecipe bukkitHandle; ++ private org.bukkit.craftbukkit.inventory.@org.jspecify.annotations.Nullable CraftMerchantRecipe bukkitHandle; + + public org.bukkit.craftbukkit.inventory.CraftMerchantRecipe asBukkit() { + return (this.bukkitHandle == null) ? this.bukkitHandle = new org.bukkit.craftbukkit.inventory.CraftMerchantRecipe(this) : this.bukkitHandle; @@ -29,11 +29,11 @@ + // CraftBukkit end private MerchantOffer( - ItemCost baseCostA, + final ItemCost baseCostA, @@ -49,6 +_,7 @@ - int demand, - float priceMultiplier, - int xp + final int demand, + final float priceMultiplier, + final int xp + , final boolean ignoreDiscounts // Paper ) { this.baseCostA = baseCostA; @@ -45,25 +45,25 @@ + this.ignoreDiscounts = ignoreDiscounts; // Paper } - public MerchantOffer(ItemCost baseCostA, ItemStack result, int maxUses, int xp, float priceMultiplier) { -@@ -75,7 +_,7 @@ - } - - public MerchantOffer(ItemCost baseCostA, Optional costB, ItemStack result, int _uses, int maxUses, int xp, float priceMultiplier, int demand) { -- this(baseCostA, costB, result, _uses, maxUses, true, 0, demand, priceMultiplier, xp); -+ this(baseCostA, costB, result, _uses, maxUses, true, 0, demand, priceMultiplier, xp, false); // Paper + public MerchantOffer(final ItemCost buy, final ItemStack result, final int maxUses, final int xp, final float priceMultiplier) { +@@ -94,7 +_,7 @@ + final float priceMultiplier, + final int demand + ) { +- this(baseCostA, costB, result, uses, maxUses, true, 0, demand, priceMultiplier, xp); ++ this(baseCostA, costB, result, uses, maxUses, true, 0, demand, priceMultiplier, xp, false); // Paper } - private MerchantOffer(MerchantOffer other) { -@@ -90,6 +_,7 @@ - other.demand, - other.priceMultiplier, - other.xp -+ , other.ignoreDiscounts // Paper + private MerchantOffer(final MerchantOffer offer) { +@@ -109,6 +_,7 @@ + offer.demand, + offer.priceMultiplier, + offer.xp ++ , offer.ignoreDiscounts // Paper ); } -@@ -125,6 +_,7 @@ +@@ -144,6 +_,7 @@ public void updateDemand() { this.demand = this.demand + this.uses - (this.maxUses - this.uses); @@ -71,16 +71,16 @@ } public ItemStack assemble() { -@@ -205,7 +_,11 @@ - if (!this.satisfiedBy(playerOfferA, playerOfferB)) { +@@ -222,7 +_,11 @@ + if (!this.satisfiedBy(buyA, buyB)) { return false; } else { -- playerOfferA.shrink(this.getCostA().getCount()); +- buyA.shrink(this.getCostA().getCount()); + // CraftBukkit start + if (!this.getCostA().isEmpty()) { -+ playerOfferA.shrink(this.getCostA().getCount()); ++ buyA.shrink(this.getCostA().getCount()); + } + // CraftBukkit end if (!this.getCostB().isEmpty()) { - playerOfferB.shrink(this.getCostB().getCount()); + buyB.shrink(this.getCostB().getCount()); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch index d8d9ad1a80df..c7a01f579a58 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/BaseCommandBlock.java +++ b/net/minecraft/world/level/BaseCommandBlock.java @@ -30,6 +_,10 @@ - @Nullable Component lastOutput; + private @Nullable Component lastOutput; private String command = ""; private @Nullable Component customName; + // CraftBukkit start @@ -11,10 +11,10 @@ public int getSuccessCount() { return this.successCount; -@@ -106,7 +_,13 @@ - this.successCount++; - } - }); +@@ -107,7 +_,13 @@ + this.successCount++; + } + }); - level.getServer().getCommands().performPrefixedCommand(commandSourceStack, this.command); + // Paper start - ServerCommandEvent + org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command)); @@ -25,19 +25,19 @@ + // Paper end - ServerCommandEvent } } catch (Throwable var7) { - CrashReport crashReport = CrashReport.forThrowable(var7, "Executing command block"); -@@ -127,8 +_,8 @@ + CrashReport report = CrashReport.forThrowable(var7, "Executing command block"); +@@ -128,8 +_,8 @@ } } -- private BaseCommandBlock.@Nullable CloseableCommandBlockSource createSource(ServerLevel level) { +- private BaseCommandBlock.@Nullable CloseableCommandBlockSource createSource(final ServerLevel level) { - return this.trackOutput ? new BaseCommandBlock.CloseableCommandBlockSource(level) : null; -+ public BaseCommandBlock.CloseableCommandBlockSource createSource(ServerLevel level) { // Paper - public, remove nullable ++ public BaseCommandBlock.CloseableCommandBlockSource createSource(final ServerLevel level) { // Paper - public, remove nullable + return new BaseCommandBlock.CloseableCommandBlockSource(level, this.trackOutput); // Paper - add back source when output disabled } public Component getName() { -@@ -161,13 +_,21 @@ +@@ -162,15 +_,23 @@ public abstract boolean isValid(); @@ -51,6 +51,8 @@ + // Paper start - add back source when output disabled + private final boolean trackOutput; + public CloseableCommandBlockSource(final ServerLevel level, final boolean trackOutput) { + Objects.requireNonNull(BaseCommandBlock.this); + super(); this.level = level; + this.trackOutput = trackOutput; + } @@ -61,7 +63,7 @@ } @Override -@@ -177,7 +_,7 @@ +@@ -180,7 +_,7 @@ @Override public boolean acceptsFailure() { @@ -70,17 +72,17 @@ } @Override -@@ -187,7 +_,8 @@ +@@ -190,7 +_,8 @@ @Override - public void sendSystemMessage(Component message) { + public void sendSystemMessage(final Component message) { - if (!this.closed) { + if (this.trackOutput && !this.closed) { // Paper - add back source when output disabled + org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks BaseCommandBlock.this.lastOutput = Component.literal("[" + TIME_FORMAT.format(ZonedDateTime.now()) + "] ").append(message); BaseCommandBlock.this.onUpdated(this.level); } -@@ -197,5 +_,12 @@ +@@ -200,5 +_,12 @@ public void close() throws Exception { this.closed = true; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch index e2911c4452ff..df4955477bdd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch @@ -6,21 +6,21 @@ public int spawnRange = 4; + private int tickDelay = 0; // Paper - Configurable mob spawner tick rate - public void setEntityId(EntityType type, @Nullable Level level, RandomSource random, BlockPos pos) { + public void setEntityId(final EntityType type, final @Nullable Level level, final RandomSource random, final BlockPos pos) { this.getOrCreateNextSpawnData(level, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString()); + this.spawnPotentials = WeightedList.of(); // CraftBukkit - SPIGOT-3496, MC-92282 } - public boolean isNearPlayer(Level level, BlockPos pos) { + public boolean isNearPlayer(final Level level, final BlockPos pos) { - return level.hasNearbyAlivePlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, this.requiredPlayerRange); + return level.hasNearbyAlivePlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, this.requiredPlayerRange); // Paper - Affects Spawning API } - public void clientTick(Level level, BlockPos pos) { + public void clientTick(final Level level, final BlockPos pos) { @@ -81,13 +_,19 @@ } - public void serverTick(ServerLevel level, BlockPos pos) { + public void serverTick(final ServerLevel level, final BlockPos pos) { + if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick + // Paper start - Configurable mob spawner tick rate + if (spawnDelay > 0 && --tickDelay > 0) return; @@ -37,7 +37,7 @@ - this.spawnDelay--; + this.spawnDelay -= tickDelay; // Paper - Configurable mob spawner tick rate } else { - boolean flag = false; + boolean delay = false; RandomSource random = level.getRandom(); @@ -125,6 +_,21 @@ continue; @@ -45,12 +45,12 @@ + // Paper start - PreCreatureSpawnEvent + com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent( -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(vec3, level), -+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, level), ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entityType.get()), + org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level) + ); + if (!event.callEvent()) { -+ flag = true; ++ delay = true; + if (event.shouldAbortSpawn()) { + break; + } @@ -58,10 +58,10 @@ + } + // Paper end - PreCreatureSpawnEvent + - Entity entity = EntityType.loadEntityRecursive(valueInput, level, EntitySpawnReason.SPAWNER, entity1 -> { - entity1.snapTo(vec3.x, vec3.y, vec3.z, entity1.getYRot(), entity1.getXRot()); - return entity1; -@@ -158,9 +_,22 @@ + Entity entity = EntityType.loadEntityRecursive(input, level, EntitySpawnReason.SPAWNER, e -> { + e.snapTo(spawnPos.x, spawnPos.y, spawnPos.z, e.getYRot(), e.getXRot()); + return e; +@@ -159,9 +_,22 @@ } nextSpawnData.getEquipment().ifPresent(mob::equip); @@ -76,7 +76,7 @@ + // Paper start + entity.spawnedViaMobSpawner = true; + entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; -+ flag = true; ++ delay = true; + if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) { + continue; + } @@ -85,22 +85,22 @@ this.delay(level, pos); return; } -@@ -171,7 +_,7 @@ +@@ -172,7 +_,7 @@ ((Mob)entity).spawnAnim(); } -- flag = true; -+ //flag = true; // Paper - moved up above cancellable event +- delay = true; ++ // delay = true; // Paper - moved up above cancellable event } } } -@@ -198,12 +_,14 @@ +@@ -199,12 +_,14 @@ } - public void load(@Nullable Level level, BlockPos pos, ValueInput input) { + public void load(final @Nullable Level level, final BlockPos pos, final ValueInput input) { - this.spawnDelay = input.getShortOr("Delay", (short)20); + this.spawnDelay = input.getIntOr("Paper.Delay", input.getShortOr("Delay", (short) 20)); // Paper - use int if set - input.read("SpawnData", SpawnData.CODEC).ifPresent(spawnData -> this.setNextSpawnData(level, pos, spawnData)); + input.read("SpawnData", SpawnData.CODEC).ifPresent(nextSpawnData -> this.setNextSpawnData(level, pos, nextSpawnData)); this.spawnPotentials = input.read("SpawnPotentials", SpawnData.LIST_CODEC) .orElseGet(() -> WeightedList.of(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData())); - this.minSpawnDelay = input.getIntOr("MinSpawnDelay", 200); @@ -112,10 +112,10 @@ this.spawnCount = input.getIntOr("SpawnCount", 4); this.maxNearbyEntities = input.getIntOr("MaxNearbyEntities", 6); this.requiredPlayerRange = input.getIntOr("RequiredPlayerRange", 16); -@@ -212,9 +_,19 @@ +@@ -213,9 +_,19 @@ } - public void save(ValueOutput output) { + public void save(final ValueOutput output) { - output.putShort("Delay", (short)this.spawnDelay); - output.putShort("MinSpawnDelay", (short)this.minSpawnDelay); - output.putShort("MaxSpawnDelay", (short)this.maxSpawnDelay); diff --git a/paper-server/patches/sources/net/minecraft/world/level/BlockGetter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/BlockGetter.java.patch index aedc95f317ab..8de5af2e6bd0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/BlockGetter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/BlockGetter.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/BlockGetter.java @@ -31,6 +_,17 @@ - BlockState getBlockState(BlockPos pos); + BlockState getBlockState(final BlockPos pos); + // Paper start - if loaded util + @Nullable BlockState getBlockStateIfLoaded(BlockPos pos); @@ -17,53 +17,47 @@ + FluidState getFluidState(BlockPos pos); - default int getLightEmission(BlockPos pos) { -@@ -64,10 +_,25 @@ - ); + default int getLightEmission(final BlockPos pos) { +@@ -63,9 +_,26 @@ } -- default BlockHitResult clip(ClipContext context) { -- return traverseBlocks(context.getFrom(), context.getTo(), context, (traverseContext, traversePos) -> { -- BlockState blockState = this.getBlockState(traversePos); -- FluidState fluidState = this.getFluidState(traversePos); -+ // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace -+ default BlockHitResult clip(ClipContext traverseContext, BlockPos traversePos) { + default BlockHitResult clip(final ClipContext c) { +- return traverseBlocks(c.getFrom(), c.getTo(), c, (context, pos) -> { +- BlockState blockState = this.getBlockState(pos); +- FluidState fluidState = this.getFluidState(pos); + // Paper start - Add predicate for blocks when raytracing -+ return clip(traverseContext, traversePos, null); ++ return clip(c, (java.util.function.Predicate) null); + } + -+ default BlockHitResult clip(ClipContext traverseContext, BlockPos traversePos, java.util.function.@Nullable Predicate canCollide) { -+ // Paper end - Add predicate for blocks when raytracing -+ // Paper start - Prevent raytrace from loading chunks -+ BlockState blockState = this.getBlockStateIfLoaded(traversePos); ++ default BlockHitResult clip(ClipContext c, BlockPos pos) { ++ return clip(c, pos, null); ++ } ++ ++ default BlockHitResult clip(ClipContext c, BlockPos pos, java.util.function.@Nullable Predicate canCollide) { ++ // Prevent raytrace from loading chunks ++ ClipContext context = c; ++ BlockState blockState = this.getBlockStateIfLoaded(pos); + if (blockState == null) { + // copied the last function parameter (listed below) -+ Vec3 vec3d = traverseContext.getFrom().subtract(traverseContext.getTo()); -+ -+ return BlockHitResult.miss(traverseContext.getTo(), Direction.getApproximateNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(traverseContext.getTo())); ++ Vec3 delta = context.getFrom().subtract(context.getTo()); ++ return BlockHitResult.miss(context.getTo(), Direction.getApproximateNearest(delta.x, delta.y, delta.z), BlockPos.containing(c.getTo())); + } + // Paper end - Prevent raytrace from loading chunks -+ if (blockState.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, traversePos)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate ++ if (blockState.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, pos)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate + FluidState fluidState = blockState.getFluidState(); // Paper - Perf: don't need to go to world state again - Vec3 from = traverseContext.getFrom(); - Vec3 to = traverseContext.getTo(); - VoxelShape blockShape = traverseContext.getBlockShape(blockState, this, traversePos); -@@ -77,6 +_,18 @@ - double d = blockHitResult == null ? Double.MAX_VALUE : traverseContext.getFrom().distanceToSqr(blockHitResult.getLocation()); - double d1 = blockHitResult1 == null ? Double.MAX_VALUE : traverseContext.getFrom().distanceToSqr(blockHitResult1.getLocation()); - return d <= d1 ? blockHitResult : blockHitResult1; -+ } -+ // CraftBukkit end -+ -+ default BlockHitResult clip(ClipContext context) { -+ // Paper start - Add predicate for blocks when raytracing -+ return clip(context, (java.util.function.Predicate) null); + Vec3 from = context.getFrom(); + Vec3 to = context.getTo(); + VoxelShape blockShape = context.getBlockShape(blockState, this, pos); +@@ -75,6 +_,12 @@ + double blockDistanceSquared = blockResult == null ? Double.MAX_VALUE : context.getFrom().distanceToSqr(blockResult.getLocation()); + double liquidDistanceSquared = liquidResult == null ? Double.MAX_VALUE : context.getFrom().distanceToSqr(liquidResult.getLocation()); + return blockDistanceSquared <= liquidDistanceSquared ? blockResult : liquidResult; + } + -+ default BlockHitResult clip(ClipContext context, java.util.function.@Nullable Predicate canCollide) { ++ default BlockHitResult clip(ClipContext c, java.util.function.@Nullable Predicate canCollide) { + // Paper end - Add predicate for blocks when raytracing -+ return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> { -+ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing - }, failContext -> { - Vec3 vec3 = failContext.getFrom().subtract(failContext.getTo()); - return BlockHitResult.miss(failContext.getTo(), Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z), BlockPos.containing(failContext.getTo())); ++ return traverseBlocks(c.getFrom(), c.getTo(), c, (context, pos) -> { ++ return this.clip(context, pos, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing + }, context -> { + Vec3 delta = context.getFrom().subtract(context.getTo()); + return BlockHitResult.miss(context.getTo(), Direction.getApproximateNearest(delta.x, delta.y, delta.z), BlockPos.containing(context.getTo())); diff --git a/paper-server/patches/sources/net/minecraft/world/level/ChunkPos.java.patch b/paper-server/patches/sources/net/minecraft/world/level/ChunkPos.java.patch index beab64a5ad72..7b6feb28b42c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/ChunkPos.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/ChunkPos.java.patch @@ -1,39 +1,29 @@ --- a/net/minecraft/world/level/ChunkPos.java +++ b/net/minecraft/world/level/ChunkPos.java -@@ -47,6 +_,7 @@ - public static final int REGION_MAX_INDEX = 31; - public final int x; - public final int z; -+ public final long longKey; // Paper - private static final int HASH_A = 1664525; - private static final int HASH_C = 1013904223; - private static final int HASH_Z_XOR = -559038737; -@@ -54,16 +_,19 @@ - public ChunkPos(int x, int z) { - this.x = x; - this.z = z; -+ this.longKey = asLong(this.x, this.z); // Paper - } - - public ChunkPos(BlockPos pos) { - this.x = SectionPos.blockToSectionCoord(pos.getX()); - this.z = SectionPos.blockToSectionCoord(pos.getZ()); -+ this.longKey = asLong(this.x, this.z); // Paper - } - - public ChunkPos(long packedPos) { - this.x = (int)packedPos; - this.z = (int)(packedPos >> 32); -+ this.longKey = asLong(this.x, this.z); // Paper - } +@@ -17,7 +_,16 @@ + import net.minecraft.world.level.chunk.status.ChunkStatus; + import org.jspecify.annotations.Nullable; - public static ChunkPos minFromRegion(int chunkX, int chunkZ) { -@@ -83,7 +_,7 @@ +-public record ChunkPos(int x, int z) { ++// Paper start ++public record ChunkPos(int x, int z, long longKey) { ++ public ChunkPos(int x, int z) { ++ this(x, z, pack(x, z)); ++ } ++ ++ public ChunkPos { ++ longKey = pack(x, z); // override if people mess around with longKey ++ } ++ // Paper end + public static final Codec CODEC = Codec.INT_STREAM + .comapFlatMap(input -> Util.fixedSize(input, 2).map(ints -> new ChunkPos(ints[0], ints[1])), pos -> IntStream.of(pos.x, pos.z)) + .stable(); +@@ -72,7 +_,7 @@ } - public long toLong() { -- return asLong(this.x, this.z); + public long pack() { +- return pack(this.x, this.z); + return this.longKey; // Paper } - public static long asLong(int x, int z) { + public static long pack(final int x, final int z) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/ClipContext.java.patch b/paper-server/patches/sources/net/minecraft/world/level/ClipContext.java.patch index b5967d32843e..d7ddcef18266 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/ClipContext.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/ClipContext.java.patch @@ -3,9 +3,9 @@ @@ -26,7 +_,7 @@ private final CollisionContext collisionContext; - public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, Entity entity) { + public ClipContext(final Vec3 from, final Vec3 to, final ClipContext.Block block, final ClipContext.Fluid fluid, final Entity entity) { - this(from, to, block, fluid, CollisionContext.of(entity)); + this(from, to, block, fluid, (entity == null) ? CollisionContext.empty() : CollisionContext.of(entity)); // CraftBukkit } - public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, CollisionContext collisionContext) { + public ClipContext(final Vec3 from, final Vec3 to, final ClipContext.Block block, final ClipContext.Fluid fluid, final CollisionContext collisionContext) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockAndTintGetter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockAndTintGetter.java.patch deleted file mode 100644 index 282491c93436..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockAndTintGetter.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/world/level/EmptyBlockAndTintGetter.java -+++ b/net/minecraft/world/level/EmptyBlockAndTintGetter.java -@@ -38,6 +_,18 @@ - return Blocks.AIR.defaultBlockState(); - } - -+ // Paper start -+ @Override -+ public @Nullable BlockState getBlockStateIfLoaded(final BlockPos pos) { -+ return null; -+ } -+ -+ @Override -+ public @Nullable FluidState getFluidIfLoaded(final BlockPos pos) { -+ return null; -+ } -+ // Paper end -+ - @Override - public FluidState getFluidState(BlockPos pos) { - return Fluids.EMPTY.defaultFluidState(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockGetter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockGetter.java.patch index 690108e9358e..06020d84243e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockGetter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/EmptyBlockGetter.java.patch @@ -17,5 +17,5 @@ + // Paper end + @Override - public BlockState getBlockState(BlockPos pos) { + public BlockState getBlockState(final BlockPos pos) { return Blocks.AIR.defaultBlockState(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch index 1ae5d9e064ff..e5eb23c97b83 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch @@ -5,45 +5,41 @@ } + // Paper start - Affects Spawning API -+ default @Nullable Player findNearbyPlayer(Entity entity, double maxDistance, @Nullable Predicate predicate) { -+ return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), maxDistance, predicate); ++ default @Nullable Player findNearbyPlayer(Entity entity, double range, @Nullable Predicate predicate) { ++ return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), range, predicate); + } + // Paper end - Affects Spawning API + - default @Nullable Player getNearestPlayer(double x, double y, double z, double distance, @Nullable Predicate predicate) { - double d = -1.0; - Player player = null; -@@ -88,6 +_,28 @@ - return player; + default @Nullable Player getNearestPlayer(final double x, final double y, final double z, final double range, final @Nullable Predicate predicate) { + double best = -1.0; + Player result = null; +@@ -88,6 +_,24 @@ + return result; } + // Paper start -+ default List findNearbyBukkitPlayers(double x, double y, double z, double radius, boolean notSpectator) { -+ return findNearbyBukkitPlayers(x, y, z, radius, notSpectator ? EntitySelector.NO_SPECTATORS : net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR); -+ } -+ -+ default List findNearbyBukkitPlayers(double x, double y, double z, double radius, @Nullable Predicate predicate) { -+ com.google.common.collect.ImmutableList.Builder builder = com.google.common.collect.ImmutableList.builder(); ++ default List findNearbyBukkitPlayers(double x, double y, double z, double range, @Nullable Predicate predicate) { ++ ImmutableList.Builder players = ImmutableList.builder(); + -+ for (Player human : this.players()) { -+ if (predicate == null || predicate.test(human)) { -+ double distanceSquared = human.distanceToSqr(x, y, z); ++ for (Player player : this.players()) { ++ if (predicate == null || predicate.test(player)) { ++ double dist = player.distanceToSqr(x, y, z); + -+ if (radius < 0.0D || distanceSquared < radius * radius) { -+ builder.add(human.getBukkitEntity()); ++ if (range < 0.0 || dist < range * range) { ++ players.add(player.getBukkitEntity()); + } + } + } + -+ return builder.build(); ++ return players.build(); + } + // Paper end + - default @Nullable Player getNearestPlayer(Entity entity, double distance) { - return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), distance, false); + default @Nullable Player getNearestPlayer(final Entity source, final double maxDist) { + return this.getNearestPlayer(source.getX(), source.getY(), source.getZ(), maxDist, false); } @@ -97,6 +_,25 @@ - return this.getNearestPlayer(x, y, z, distance, predicate); + return this.getNearestPlayer(x, y, z, maxDist, predicate); } + // Paper start - Affects Spawning API @@ -56,7 +52,7 @@ + for (Player player : this.players()) { + if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) { // combines NO_SPECTATORS and LIVING_ENTITY_STILL_ALIVE with an "affects spawning" check + double playerDist = player.distanceToSqr(x, y, z); -+ if (range < 0.0D || playerDist < range * range) { ++ if (range < 0.0 || playerDist < range * range) { + return true; + } + } @@ -65,7 +61,7 @@ + } + // Paper end - Affects Spawning API + - default boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) { + default boolean hasNearbyAlivePlayer(final double x, final double y, final double z, final double range) { for (Player player : this.players()) { if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { @@ -120,4 +_,11 @@ diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index 6311623ded6a..420d01b7498d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -86,6 +_,16 @@ +@@ -91,6 +_,16 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import org.jspecify.annotations.Nullable; @@ -17,7 +17,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public static final Codec> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); public static final ResourceKey OVERWORLD = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("overworld")); -@@ -127,6 +_,56 @@ +@@ -132,6 +_,55 @@ private final PalettedContainerFactory palettedContainerFactory; private long subTickCount; @@ -42,7 +42,6 @@ + // Paper end - add paper world config + + public static @Nullable BlockPos lastPhysicsProblem; // Spigot -+ private int tileTickPosition; + public final Map explosionDensityCache = new java.util.HashMap<>(); // Paper - Optimize explosions + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here + @@ -72,15 +71,13 @@ + public abstract ResourceKey getTypeKey(); + protected Level( - WritableLevelData levelData, - ResourceKey dimension, -@@ -135,8 +_,24 @@ - boolean isClientSide, - boolean isDebug, - long biomeZoomSeed, -- int maxChainedNeighborUpdates -+ int maxChainedNeighborUpdates, -+ org.bukkit.generator.@Nullable ChunkGenerator generator, // Paper + final WritableLevelData levelData, + final ResourceKey dimension, +@@ -141,7 +_,23 @@ + final boolean isDebug, + final long biomeZoomSeed, + final int maxChainedNeighborUpdates ++ , org.bukkit.generator.@Nullable ChunkGenerator generator, // Paper + org.bukkit.generator.@Nullable BiomeProvider biomeProvider, // Paper + org.bukkit.World.Environment environment, // Paper + java.util.function.Function= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; + return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Paper - Diff on change warnUnsafeChunk() and isInsideBuildHeightAndWorldBoundsHorizontal } - private static boolean isInValidBoundsHorizontal(BlockPos blockPos) { -@@ -186,14 +_,79 @@ + private static boolean isInValidBoundsHorizontal(final BlockPos pos) { +@@ -191,14 +_,79 @@ return y < -20000000 || y >= 20000000; } -- public LevelChunk getChunkAt(BlockPos pos) { -+ public final LevelChunk getChunkAt(BlockPos pos) { // Paper - help inline +- public LevelChunk getChunkAt(final BlockPos pos) { ++ public final LevelChunk getChunkAt(final BlockPos pos) { // Paper - help inline return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); } @Override -- public LevelChunk getChunk(int chunkX, int chunkZ) { +- public LevelChunk getChunk(final int chunkX, final int chunkZ) { - return (LevelChunk)this.getChunk(chunkX, chunkZ, ChunkStatus.FULL); - } -+ public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline ++ public final LevelChunk getChunk(final int chunkX, final int chunkZ) { // Paper - final to help inline + // Paper start - Perf: make sure loaded chunks get the inlined variant of this function + net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource(); + LevelChunk ifLoaded = cps.getChunkAtIfLoadedImmediately(chunkX, chunkZ); @@ -234,11 +231,11 @@ + + @Override + public final boolean hasChunkAt(BlockPos pos) { -+ return getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4) != null; // Paper - Perf: Optimize Level.hasChunkAt(BlockPosition)Z ++ return this.getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4) != null; // Paper - Perf: Optimize Level.hasChunkAt(BlockPosition)Z + } + + public final boolean isLoadedAndInBounds(BlockPos pos) { // Paper - final for inline -+ return getWorldBorder().isWithinBounds(pos) && getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) != null; ++ return this.getWorldBorder().isWithinBounds(pos) && this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) != null; + } + + public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { // Overridden in ServerLevel for ABI compat which has final @@ -251,16 +248,16 @@ + + // reduces need to do isLoaded before getType + public final @Nullable BlockState getBlockStateIfLoadedAndInBounds(BlockPos pos) { -+ return getWorldBorder().isWithinBounds(pos) ? getBlockStateIfLoaded(pos) : null; ++ return this.getWorldBorder().isWithinBounds(pos) ? this.getBlockStateIfLoaded(pos) : null; + } + // Paper end @Override - public @Nullable ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) { -@@ -212,6 +_,22 @@ + public @Nullable ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus status, final boolean loadOrGenerate) { +@@ -217,6 +_,22 @@ @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, int recursionLeft) { + public boolean setBlock(final BlockPos pos, final BlockState blockState, @Block.UpdateFlags final int updateFlags, final int updateLimit) { + // CraftBukkit start - tree generation + if (this.captureTreeGeneration) { + // Paper start - Protect Bedrock and End Portal/Frames from being destroyed @@ -269,21 +266,21 @@ + // Paper end - Protect Bedrock and End Portal/Frames from being destroyed + CraftBlockState blockstate = this.capturedBlockStates.get(pos); + if (blockstate == null) { -+ blockstate = org.bukkit.craftbukkit.block.CapturedBlockState.getTreeBlockState(this, pos, flags); ++ blockstate = org.bukkit.craftbukkit.block.CapturedBlockState.getTreeBlockState(this, pos, updateFlags); + this.capturedBlockStates.put(pos.immutable(), blockstate); + } -+ blockstate.setData(state); -+ blockstate.setFlags(flags); ++ blockstate.setBlock(blockState); ++ blockstate.setFlags(updateFlags); + return true; + } + // CraftBukkit end if (!this.isInValidBounds(pos)) { return false; } else if (!this.isClientSide() && this.isDebug()) { -@@ -219,11 +_,31 @@ +@@ -224,11 +_,31 @@ } else { - LevelChunk chunkAt = this.getChunkAt(pos); - Block block = state.getBlock(); + LevelChunk chunk = this.getChunkAt(pos); + Block block = blockState.getBlock(); + // CraftBukkit start - capture blockstates + boolean captured = false; + if (this.captureBlockStates) { @@ -295,11 +292,11 @@ + } else { + snapshot = this.capturedBlockStates.get(pos); + } -+ snapshot.setFlags(flags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags ++ snapshot.setFlags(updateFlags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags + } - BlockState blockState = chunkAt.setBlockState(pos, state, flags); -+ // CraftBukkit end - if (blockState == null) { ++ // CraftBukkit end - capture blockstates + BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); + if (oldState == null) { + // CraftBukkit start - remove blockstate if failed (or the same) + if (this.captureBlockStates && captured) { + this.capturedBlockStates.remove(pos); @@ -307,23 +304,23 @@ + // CraftBukkit end return false; } else { - BlockState blockState1 = this.getBlockState(pos); -+ /* - if (blockState1 == state) { - if (blockState != blockState1) { - this.setBlocksDirty(pos, blockState, blockState1); -@@ -251,12 +_,68 @@ + BlockState newState = this.getBlockState(pos); ++ /* // CraftBukkit + if (newState == blockState) { + if (oldState != newState) { + this.setBlocksDirty(pos, oldState, newState); +@@ -256,12 +_,69 @@ - this.updatePOIOnBlockStateChange(pos, blockState, blockState1); + this.updatePOIOnBlockStateChange(pos, oldState, newState); } -+ */ ++ */ // CraftBukkit + + // CraftBukkit start + if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates + // Modularize client and physic updates + // Spigot start + try { -+ this.notifyAndUpdatePhysics(pos, chunkAt, blockState, state, blockState1, flags, recursionLeft); ++ this.notifyAndUpdatePhysics(pos, chunk, oldState, blockState, newState, updateFlags, updateLimit); + } catch (StackOverflowError ex) { + Level.lastPhysicsProblem = pos.immutable(); + } @@ -364,7 +361,7 @@ + blockState.updateIndirectNeighbourShapes(this, pos, i, recursionLeft - 1); // Don't call an event for the old block to limit event spam + boolean cancelledUpdates = false; // Paper - Fix block place logic + if (((ServerLevel)this).hasPhysicsEvent) { // Paper - BlockPhysicsEvent -+ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), CraftBlockData.fromData(state)); ++ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), state.asBlockData()); + cancelledUpdates = !event.callEvent(); // Paper - Fix block place logic + } + // CraftBukkit end @@ -378,10 +375,18 @@ + } + } + // CraftBukkit end - public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) { ++ + public void updatePOIOnBlockStateChange(final BlockPos pos, final BlockState oldState, final BlockState newState) { } -@@ -273,13 +_,31 @@ +@@ -272,19 +_,37 @@ + } + + @Override +- public boolean destroyBlock(final BlockPos pos, final boolean dropResources, final @Nullable Entity breaker, final int updateLimit) { ++ public boolean destroyBlock(final BlockPos pos, boolean dropResources, final @Nullable Entity breaker, final int updateLimit) { // Paper - make dropResources non-final + BlockState blockState = this.getBlockState(pos); + if (blockState.isAir()) { return false; } else { FluidState fluidState = this.getFluidState(pos); @@ -394,13 +399,13 @@ + BlockState effectType = blockState; + int xp = blockState.getBlock().getExpDrop(blockState, (ServerLevel) this, pos, ItemStack.EMPTY, true); + if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluidState.createLegacyBlock().createCraftBlockData(), effectType.createCraftBlockData(), xp, dropBlock); ++ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluidState.createLegacyBlock().asBlockData(), effectType.asBlockData(), xp, dropResources); + if (!event.callEvent()) { + return false; + } + effectType = ((CraftBlockData) event.getEffectBlock()).getState(); + playEffect = event.playEffect(); -+ dropBlock = event.willDrop(); ++ dropResources = event.willDrop(); + xp = event.getExpToDrop(); + } + // Paper end - BlockDestroyEvent @@ -408,18 +413,18 @@ + this.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent } - if (dropBlock) { + if (dropResources) { BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; -- Block.dropResources(blockState, this, pos, blockEntity, entity, ItemStack.EMPTY); -+ Block.dropResources(blockState, this, pos, blockEntity, entity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping -+ blockState.getBlock().popExperience((ServerLevel) this, pos, xp, entity); // Paper - Properly handle xp dropping; custom amount +- Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY); ++ Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ blockState.getBlock().popExperience((ServerLevel) this, pos, xp, breaker); // Paper - Properly handle xp dropping; custom amount } - boolean flag = this.setBlock(pos, fluidState.createLegacyBlock(), Block.UPDATE_ALL, recursionLeft); -@@ -345,10 +_,18 @@ + boolean destroyed = this.setBlock(pos, fluidState.createLegacyBlock(), Block.UPDATE_ALL, updateLimit); +@@ -359,10 +_,18 @@ @Override - public BlockState getBlockState(BlockPos pos) { + public BlockState getBlockState(final BlockPos pos) { + // CraftBukkit start - tree generation + if (this.captureTreeGeneration) { + CraftBlockState previous = this.capturedBlockStates.get(pos); // Paper @@ -436,42 +441,43 @@ return chunk.getBlockState(pos); } } -@@ -447,31 +_,47 @@ +@@ -533,31 +_,48 @@ this.pendingBlockEntityTickers.clear(); } - Iterator iterator = this.blockEntityTickers.iterator(); -+ // Spigot start - boolean runsNormally = this.tickRateManager().runsNormally(); ++ // Paper - Fix MC-117075 use removeAll - remove iterator in favour of indexed for loop, ensuring compile error if something uses iter incorrectly + boolean tickBlockEntities = this.tickRateManager().runsNormally(); - while (iterator.hasNext()) { -- TickingBlockEntity tickingBlockEntity = iterator.next(); -+ var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet(); // Paper - Fix MC-117075; use removeAll -+ toRemove.add(null); // Paper - Fix MC-117075 -+ for (this.tileTickPosition = 0; this.tileTickPosition < this.blockEntityTickers.size(); this.tileTickPosition++) { // Paper - Disable tick limiters -+ TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition); -+ // Spigot end - if (tickingBlockEntity.isRemoved()) { +- TickingBlockEntity ticker = iterator.next(); ++ // Paper start - Fix MC-117075 use removeAll ++ final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<@Nullable TickingBlockEntity> toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); ++ toRemove.add(null); ++ for (int tickerIndex = 0; tickerIndex < this.blockEntityTickers.size(); tickerIndex++) { ++ final TickingBlockEntity ticker = this.blockEntityTickers.get(tickerIndex); ++ // Paper end - Fix MC-117075 use removeAll + if (ticker.isRemoved()) { - iterator.remove(); -+ toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll - } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { - tickingBlockEntity.tick(); ++ toRemove.add(ticker); // Paper - Fix MC-117075 use removeAll + } else if (tickBlockEntities && this.shouldTickBlocksAt(ticker.getPos())) { + ticker.tick(); } } -+ this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 ++ this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 use removeAll this.tickingBlockEntities = false; + this.spigotConfig.currentPrimedTnt = 0; // Spigot } - public void guardEntityTick(Consumer action, T entity) { + public void guardEntityTick(final Consumer tick, final T entity) { try { - action.accept(entity); + tick.accept(entity); } catch (Throwable var6) { -- CrashReport crashReport = CrashReport.forThrowable(var6, "Ticking entity"); -- CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being ticked"); -- entity.fillCrashReportCategory(crashReportCategory); -- throw new ReportedException(crashReport); +- CrashReport report = CrashReport.forThrowable(var6, "Ticking entity"); +- CrashReportCategory category = report.addCategory("Entity being ticked"); +- entity.fillCrashReportCategory(category); +- throw new ReportedException(report); + // Paper start - Prevent block entity and entity crashes + final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); + MinecraftServer.LOGGER.error(msg, var6); @@ -490,12 +496,12 @@ + } + // Paper end - Option to prevent armor stands from doing entity lookups - public boolean shouldTickDeath(Entity entity) { + public boolean shouldTickDeath(final Entity entity) { return true; -@@ -595,6 +_,12 @@ +@@ -691,6 +_,12 @@ @Override - public @Nullable BlockEntity getBlockEntity(BlockPos pos) { + public @Nullable BlockEntity getBlockEntity(final BlockPos pos) { + // Paper start - Perf: Optimize capturedTileEntities lookup + net.minecraft.world.level.block.entity.BlockEntity blockEntity; + if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) { @@ -505,20 +511,20 @@ if (!this.isInValidBounds(pos)) { return null; } else { -@@ -607,6 +_,12 @@ - public void setBlockEntity(BlockEntity blockEntity) { - BlockPos blockPos = blockEntity.getBlockPos(); - if (this.isInValidBounds(blockPos)) { +@@ -703,6 +_,12 @@ + public void setBlockEntity(final BlockEntity blockEntity) { + BlockPos pos = blockEntity.getBlockPos(); + if (this.isInValidBounds(pos)) { + // CraftBukkit start + if (this.captureBlockStates) { -+ this.capturedTileEntities.put(blockPos.immutable(), blockEntity); ++ this.capturedTileEntities.put(pos.immutable(), blockEntity); + return; + } + // CraftBukkit end - this.getChunkAt(blockPos).addAndRegisterBlockEntity(blockEntity); + this.getChunkAt(pos).addAndRegisterBlockEntity(blockEntity); } } -@@ -1011,7 +_,8 @@ +@@ -1110,7 +_,8 @@ BLOCK("block"), MOB("mob"), TNT("tnt"), @@ -528,7 +534,7 @@ public static final Codec CODEC = StringRepresentable.fromEnum(Level.ExplosionInteraction::values); private final String id; -@@ -1025,4 +_,16 @@ +@@ -1124,4 +_,16 @@ return this.id; } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/LevelAccessor.java.patch b/paper-server/patches/sources/net/minecraft/world/level/LevelAccessor.java.patch index 8f8e291a66b5..6ca294681955 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/LevelAccessor.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/LevelAccessor.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/LevelAccessor.java +++ b/net/minecraft/world/level/LevelAccessor.java -@@ -97,4 +_,6 @@ - default void gameEvent(ResourceKey gameEvent, BlockPos pos, GameEvent.Context context) { +@@ -102,4 +_,6 @@ + default void gameEvent(final ResourceKey gameEvent, final BlockPos pos, final GameEvent.Context context) { this.gameEvent(this.registryAccess().lookupOrThrow(Registries.GAME_EVENT).getOrThrow(gameEvent), pos, context); } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/LevelReader.java.patch b/paper-server/patches/sources/net/minecraft/world/level/LevelReader.java.patch index cdaaa11078c6..3af49d08cfa6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/LevelReader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/LevelReader.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/LevelReader.java +++ b/net/minecraft/world/level/LevelReader.java @@ -26,6 +_,9 @@ - public interface LevelReader extends BlockAndTintGetter, CollisionGetter, SignalGetter, BiomeManager.NoiseBiomeSource { - @Nullable ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk); + public interface LevelReader extends BlockAndLightGetter, CollisionGetter, SignalGetter, BiomeManager.NoiseBiomeSource { + @Nullable ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus targetStatus, final boolean loadOrGenerate); + @Nullable ChunkAccess getChunkIfLoadedImmediately(int x, int z); // Paper - ifLoaded api (we need this since current impl blocks if the chunk is loading) -+ @Nullable default ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);} ++ default @Nullable ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); } + @Deprecated boolean hasChunk(int chunkX, int chunkZ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/LevelSettings.java.patch b/paper-server/patches/sources/net/minecraft/world/level/LevelSettings.java.patch new file mode 100644 index 000000000000..70bf9a58d5ab --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/LevelSettings.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/level/LevelSettings.java ++++ b/net/minecraft/world/level/LevelSettings.java +@@ -51,6 +_,16 @@ + return new LevelSettings(this.levelName, this.gameType, this.difficultySettings, this.allowCommands, this.dataConfiguration); + } + ++ // Paper start ++ public LevelSettings withLevelName(String name) { ++ return new LevelSettings(name, this.gameType, this.difficultySettings, this.allowCommands, this.dataConfiguration); ++ } ++ ++ public LevelSettings withHardcore(boolean hardcore) { ++ return new LevelSettings(this.levelName, this.gameType, new LevelSettings.DifficultySettings(this.difficultySettings.difficulty(), hardcore, this.difficultySettings.locked()), this.allowCommands, this.dataConfiguration); ++ } ++ // Paper end ++ + public record DifficultySettings(Difficulty difficulty, boolean hardcore, boolean locked) { + public static final LevelSettings.DifficultySettings DEFAULT = new LevelSettings.DifficultySettings(Difficulty.NORMAL, false, false); + public static final Codec CODEC = RecordCodecBuilder.create( diff --git a/paper-server/patches/sources/net/minecraft/world/level/LevelWriter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/LevelWriter.java.patch index a132dab9b9ad..cc4fdad99784 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/LevelWriter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/LevelWriter.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/LevelWriter.java +++ b/net/minecraft/world/level/LevelWriter.java @@ -28,4 +_,10 @@ - default boolean addFreshEntity(Entity entity) { + default boolean addFreshEntity(final Entity entity) { return false; } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch index fba73eea2467..d9abff23dc29 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -76,6 +_,13 @@ +@@ -77,6 +_,13 @@ if (!(entity instanceof Mob mob && (mob.isPersistenceRequired() || mob.requiresCustomPersistence()))) { MobCategory category = entity.getType().getCategory(); if (category != MobCategory.MISC) { @@ -11,21 +11,21 @@ + continue; + } + // Paper end - Only count natural spawns - BlockPos blockPos = entity.blockPosition(); - chunkGetter.query(ChunkPos.asLong(blockPos), chunk -> { - MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType()); -@@ -100,17 +_,34 @@ + BlockPos pos = entity.blockPosition(); + chunkGetter.query(ChunkPos.pack(pos), chunk -> { + MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(pos, chunk).getMobSettings().getMobSpawnCost(entity.getType()); +@@ -101,17 +_,34 @@ return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value(); } + // CraftBukkit start - add server public static List getFilteredSpawningCategories( -- NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives -+ NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives, ServerLevel level +- final NaturalSpawner.SpawnState state, final boolean spawnFriendlies, final boolean spawnEnemies, final boolean spawnPersistent ++ final NaturalSpawner.SpawnState state, final boolean spawnFriendlies, final boolean spawnEnemies, final boolean spawnPersistent, final ServerLevel level ) { + net.minecraft.world.level.storage.LevelData worlddata = level.getLevelData(); // CraftBukkit - Other mob type spawn tick rate + // CraftBukkit end - List list = new ArrayList<>(SPAWNING_CATEGORIES.length); + List spawningCategories = new ArrayList<>(SPAWNING_CATEGORIES.length); for (MobCategory mobCategory : SPAWNING_CATEGORIES) { + // CraftBukkit start - Use per-world spawn limits @@ -43,16 +43,16 @@ + if ((spawnFriendlies || !mobCategory.isFriendly()) && (spawnEnemies || mobCategory.isFriendly()) - && (spawnPassives || !mobCategory.isPersistent()) -- && spawnState.canSpawnForCategoryGlobal(mobCategory)) { -+ && spawnState.canSpawnForCategoryGlobal(mobCategory, limit)) { // Paper - Optional per player mob spawns; remove global check, check later during the local one - list.add(mobCategory); + && (spawnPersistent || !mobCategory.isPersistent()) +- && state.canSpawnForCategoryGlobal(mobCategory)) { ++ && state.canSpawnForCategoryGlobal(mobCategory, limit)) { // Paper - Optional per player mob spawns; remove global check, check later during the local one + spawningCategories.add(mobCategory); + // CraftBukkit end } } -@@ -130,6 +_,16 @@ - profilerFiller.pop(); +@@ -133,6 +_,16 @@ + profiler.pop(); } + // Paper start - Add mobcaps commands @@ -66,64 +66,64 @@ + // Paper end - Add mobcaps commands + public static void spawnCategoryForChunk( - MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback - ) { -@@ -155,8 +_,8 @@ + final MobCategory mobCategory, + final ServerLevel level, +@@ -162,8 +_,8 @@ StructureManager structureManager = level.structureManager(); ChunkGenerator generator = level.getChunkSource().getGenerator(); - int y = pos.getY(); -- BlockState blockState = chunk.getBlockState(pos); -- if (!blockState.isRedstoneConductor(chunk, pos)) { -+ BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn -+ if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); - int i = 0; + int yStart = start.getY(); +- BlockState state = chunk.getBlockState(start); +- if (!state.isRedstoneConductor(chunk, start)) { ++ BlockState state = level.getBlockStateIfLoadedAndInBounds(start); // Paper - don't load chunks for mob spawn ++ if (state != null && !state.isRedstoneConductor(chunk, start)) { // Paper - don't load chunks for mob spawn + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + int clusterSize = 0; -@@ -178,7 +_,7 @@ - Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, false); +@@ -185,7 +_,7 @@ + Player nearestPlayer = level.getNearestPlayer(xx, yStart, zz, -1.0, false); if (nearestPlayer != null) { - double d2 = nearestPlayer.distanceToSqr(d, y, d1); -- if (isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { -+ if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn - if (spawnerData == null) { - Optional randomSpawnMobAt = getRandomSpawnMobAt( - level, structureManager, generator, category, level.random, mutableBlockPos -@@ -191,7 +_,13 @@ - ceil = spawnerData.minCount() + level.random.nextInt(1 + spawnerData.maxCount() - spawnerData.minCount()); + double nearestPlayerDistanceSqr = nearestPlayer.distanceToSqr(xx, yStart, zz); +- if (isRightDistanceToPlayerAndSpawnPoint(level, chunk, pos, nearestPlayerDistanceSqr)) { ++ if (level.isLoadedAndInBounds(pos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, pos, nearestPlayerDistanceSqr)) { // Paper - don't load chunks for mob spawn + if (currentSpawnData == null) { + Optional nextSpawnData = getRandomSpawnMobAt( + level, structureManager, generator, mobCategory, level.random, pos +@@ -198,7 +_,13 @@ + max = currentSpawnData.minCount() + level.random.nextInt(1 + currentSpawnData.maxCount() - currentSpawnData.minCount()); } -- if (isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2) +- if (isValidSpawnPostitionForType(level, mobCategory, structureManager, generator, currentSpawnData, pos, nearestPlayerDistanceSqr) + // Paper start - PreCreatureSpawnEvent -+ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2); ++ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(level, mobCategory, structureManager, generator, currentSpawnData, pos, nearestPlayerDistanceSqr); + if (doSpawning == PreSpawnStatus.ABORT) { + return; + } + if (doSpawning == PreSpawnStatus.SUCCESS + // Paper end - PreCreatureSpawnEvent - && filter.test(spawnerData.type(), mutableBlockPos, chunk)) { - Mob mobForSpawn = getMobForSpawn(level, spawnerData.type()); - if (mobForSpawn == null) { -@@ -203,10 +_,15 @@ - spawnGroupData = mobForSpawn.finalizeSpawn( - level, level.getCurrentDifficultyAt(mobForSpawn.blockPosition()), EntitySpawnReason.NATURAL, spawnGroupData + && extraTest.test(currentSpawnData.type(), pos, chunk)) { + Mob mob = getMobForSpawn(level, currentSpawnData.type()); + if (mob == null) { +@@ -210,10 +_,15 @@ + groupData = mob.finalizeSpawn( + level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.NATURAL, groupData ); -- i++; -- i3++; -- level.addFreshEntityWithPassengers(mobForSpawn); -- callback.run(mobForSpawn, chunk); +- clusterSize++; +- groupSize++; +- level.addFreshEntityWithPassengers(mob); +- spawnCallback.run(mob, chunk); + // CraftBukkit start + // SPIGOT-7045: Give ocelot babies back their special spawn reason. Note: This is the only modification required as ocelots count as monsters which means they only spawn during normal chunk ticking and do not spawn during chunk generation as starter mobs. -+ level.addFreshEntityWithPassengers(mobForSpawn, (mobForSpawn instanceof net.minecraft.world.entity.animal.feline.Ocelot && !((org.bukkit.entity.Ageable) mobForSpawn.getBukkitEntity()).isAdult()) ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OCELOT_BABY : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); -+ if (!mobForSpawn.isRemoved()) { -+ ++i; -+ ++i3; -+ callback.run(mobForSpawn, chunk); ++ level.addFreshEntityWithPassengers(mob, (mob instanceof net.minecraft.world.entity.animal.feline.Ocelot && !((org.bukkit.entity.Ageable) mob.getBukkitEntity()).isAdult()) ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OCELOT_BABY : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); ++ if (!mob.isRemoved()) { ++ clusterSize++; ++ groupSize++; ++ spawnCallback.run(mob, chunk); + } + // CraftBukkit end - if (i >= mobForSpawn.getMaxSpawnClusterSize()) { + if (clusterSize >= mob.getMaxSpawnClusterSize()) { return; } -@@ -238,7 +_,15 @@ +@@ -247,7 +_,15 @@ } } @@ -137,18 +137,19 @@ + } + private static PreSpawnStatus isValidSpawnPostitionForType( + // Paper end - PreCreatureSpawnEvent - ServerLevel level, - MobCategory category, - StructureManager structureManager, -@@ -248,7 +_,19 @@ - double distance + final ServerLevel level, + final MobCategory mobCategory, + final StructureManager structureManager, +@@ -256,14 +_,27 @@ + final BlockPos.MutableBlockPos pos, + final double nearestPlayerDistanceSqr ) { - EntityType entityType = data.type(); -- return entityType.getCategory() != MobCategory.MISC + // Paper start - PreCreatureSpawnEvent + EntityType type = currentSpawnData.type(); +- return type.getCategory() != MobCategory.MISC + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( + org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), -+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entityType), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(type), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL + ); + if (!event.callEvent()) { + if (event.shouldAbortSpawn()) { @@ -156,28 +157,27 @@ + } + return PreSpawnStatus.CANCELLED; + } -+ final boolean success = entityType.getCategory() != MobCategory.MISC ++ final boolean success = type.getCategory() != MobCategory.MISC + // Paper end - PreCreatureSpawnEvent - && ( - entityType.canSpawnFarFromPlayer() - || !(distance > entityType.getCategory().getDespawnDistance() * entityType.getCategory().getDespawnDistance()) -@@ -258,6 +_,7 @@ - && SpawnPlacements.isSpawnPositionOk(entityType, level, pos) - && SpawnPlacements.checkSpawnRules(entityType, level, EntitySpawnReason.NATURAL, pos, level.random) - && level.noCollision(entityType.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5)); + && (type.canSpawnFarFromPlayer() || !(nearestPlayerDistanceSqr > type.getCategory().getDespawnDistance() * type.getCategory().getDespawnDistance())) + && type.canSummon() + && canSpawnMobAt(level, structureManager, generator, mobCategory, currentSpawnData, pos) + && SpawnPlacements.isSpawnPositionOk(type, level, pos) + && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.NATURAL, pos, level.random) + && level.noCollision(type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5)); + return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent } - private static @Nullable Mob getMobForSpawn(ServerLevel level, EntityType entityType) { -@@ -269,6 +_,7 @@ - LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(entityType)); + private static @Nullable Mob getMobForSpawn(final ServerLevel level, final EntityType type) { +@@ -275,6 +_,7 @@ + LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type)); } catch (Exception var4) { LOGGER.warn("Failed to create mob", (Throwable)var4); + com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var4); // Paper - ServerExceptionEvent } return null; -@@ -375,6 +_,7 @@ +@@ -402,6 +_,7 @@ entity = spawnerData.type().create(level.getLevel(), EntitySpawnReason.NATURAL); } catch (Exception var27) { LOGGER.warn("Failed to create mob", (Throwable)var27); @@ -185,25 +185,25 @@ continue; } -@@ -389,7 +_,7 @@ - spawnGroupData = mob.finalizeSpawn( - level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, spawnGroupData +@@ -416,7 +_,7 @@ + groupSpawnData = mob.finalizeSpawn( + level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, groupSpawnData ); - level.addFreshEntityWithPassengers(mob); + level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - flag = true; + success = true; } } -@@ -507,8 +_,10 @@ +@@ -534,8 +_,10 @@ return this.unmodifiableMobCategoryCounts; } -- boolean canSpawnForCategoryGlobal(MobCategory category) { -- int i = category.getMaxInstancesPerChunk() * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; +- private boolean canSpawnForCategoryGlobal(final MobCategory mobCategory) { +- int maxMobCount = mobCategory.getMaxInstancesPerChunk() * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; + // CraftBukkit start -+ boolean canSpawnForCategoryGlobal(MobCategory category, int limit) { -+ int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; ++ private boolean canSpawnForCategoryGlobal(final MobCategory mobCategory, final int limit) { ++ int maxMobCount = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; + // CraftBukkit end - return this.mobCategoryCounts.getInt(category) < i; + return this.mobCategoryCounts.getInt(mobCategory) < maxMobCount; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch b/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch index 8d1de8e39400..fd876791f3b9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/level/PathNavigationRegion.java +++ b/net/minecraft/world/level/PathNavigationRegion.java @@ -66,13 +_,41 @@ - private ChunkAccess getChunk(int x, int z) { - int i = x - this.centerX; - int i1 = z - this.centerZ; -- if (i >= 0 && i < this.chunks.length && i1 >= 0 && i1 < this.chunks[i].length) { -+ if (i >= 0 && i < this.chunks.length && i1 >= 0 && i1 < this.chunks[i].length) { // Paper - if this changes, update getChunkIfLoaded below - ChunkAccess chunkAccess = this.chunks[i][i1]; - return (ChunkAccess)(chunkAccess != null ? chunkAccess : new EmptyLevelChunk(this.level, new ChunkPos(x, z), this.plains.get())); + private ChunkAccess getChunk(final int chunkX, final int chunkZ) { + int xc = chunkX - this.centerX; + int zc = chunkZ - this.centerZ; +- if (xc >= 0 && xc < this.chunks.length && zc >= 0 && zc < this.chunks[xc].length) { ++ if (xc >= 0 && xc < this.chunks.length && zc >= 0 && zc < this.chunks[xc].length) { // Paper - if this changes, update getChunkIfLoaded below + ChunkAccess chunk = this.chunks[xc][zc]; + return (ChunkAccess)(chunk != null ? chunk : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get())); } else { - return new EmptyLevelChunk(this.level, new ChunkPos(x, z), this.plains.get()); + return new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()); } } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch b/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch index 13b279e590cf..4da082778cff 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch @@ -1,20 +1,5 @@ --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -36,6 +_,14 @@ - import net.minecraft.world.phys.Vec3; - import org.jspecify.annotations.Nullable; - -+// CraftBukkit start -+import net.minecraft.world.entity.boss.enderdragon.EnderDragonPart; -+import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.craftbukkit.util.CraftLocation; -+import org.bukkit.Location; -+// CraftBukkit end -+ - public class ServerExplosion implements Explosion { - private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); - private static final int MAX_DROPS_PER_COMBINED_STACK = 16; @@ -49,6 +_,11 @@ private final DamageSource damageSource; private final ExplosionDamageCalculator damageCalculator; @@ -26,7 +11,7 @@ + public boolean excludeSourceFromDamage = true; // Paper - Allow explosions to damage source public ServerExplosion( - ServerLevel level, + final ServerLevel level, @@ -68,6 +_,10 @@ this.blockInteraction = blockInteraction; this.damageSource = damageSource == null ? level.damageSources().explosion(this) : damageSource; @@ -37,52 +22,52 @@ + // Paper end - add yield } - private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) { + private ExplosionDamageCalculator makeDamageCalculator(final @Nullable Entity source) { @@ -141,7 +_,8 @@ - for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { - BlockPos blockPos = BlockPos.containing(d3, d4, d5); - BlockState blockState = this.level.getBlockState(blockPos); -- FluidState fluidState = this.level.getFluidState(blockPos); -+ if (!blockState.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed -+ FluidState fluidState = blockState.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions - if (!this.level.isInWorldBounds(blockPos)) { + for (float stepSize = 0.3F; remainingPower > 0.0F; remainingPower -= 0.22500001F) { + BlockPos pos = BlockPos.containing(xp, yp, zp); + BlockState block = this.level.getBlockState(pos); +- FluidState fluid = this.level.getFluidState(pos); ++ if (!block.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed ++ FluidState fluid = block.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions + if (!this.level.isInWorldBounds(pos)) { break; } -@@ -154,6 +_,15 @@ +@@ -153,6 +_,15 @@ - if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockPos, blockState, f)) { - set.add(blockPos); + if (remainingPower > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, pos, block, remainingPower)) { + toBlowSet.add(pos); + // Paper start - prevent headless pistons from forming -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && blockState.is(net.minecraft.world.level.block.Blocks.MOVING_PISTON)) { -+ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockPos); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && block.is(net.minecraft.world.level.block.Blocks.MOVING_PISTON)) { ++ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(pos); + if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) { -+ net.minecraft.core.Direction direction = blockState.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); -+ set.add(blockPos.relative(direction.getOpposite())); ++ net.minecraft.core.Direction direction = block.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING); ++ toBlowSet.add(pos.relative(direction.getOpposite())); + } + } + // Paper end - prevent headless pistons from forming } - d3 += d * 0.3F; -@@ -177,8 +_,8 @@ - int floor3 = Mth.floor(this.center.y + f + 1.0); - int floor4 = Mth.floor(this.center.z - f - 1.0); - int floor5 = Mth.floor(this.center.z + f + 1.0); -- -- for (Entity entity : this.level.getEntities(this.source, new AABB(floor, floor2, floor4, floor1, floor3, floor5))) { -+ List list = this.level.getEntities(this.excludeSourceFromDamage ? this.source : null, new AABB(floor, floor2, floor4, floor1, floor3, floor5), entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source + xp += xd * 0.3F; +@@ -176,8 +_,9 @@ + int y1 = Mth.floor(this.center.y + doubleRadius + 1.0); + int z0 = Mth.floor(this.center.z - doubleRadius - 1.0); + int z1 = Mth.floor(this.center.z + doubleRadius + 1.0); ++ List list = this.level.getEntities(this.excludeSourceFromDamage ? this.source : null, new AABB(x0, y0, z0, x1, y1, z1), entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source + +- for (Entity entity : this.level.getEntities(this.source, new AABB(x0, y0, z0, x1, y1, z1))) { + for (Entity entity : list) { // Paper - used in loop if (!entity.ignoreExplosion(this)) { - double d = Math.sqrt(entity.distanceToSqr(this.center)) / f; - if (!(d > 1.0)) { -@@ -186,20 +_,56 @@ - Vec3 vec31 = vec3.subtract(this.center).normalize(); + double dist = Math.sqrt(entity.distanceToSqr(this.center)) / doubleRadius; + if (!(dist > 1.0)) { +@@ -185,20 +_,56 @@ + Vec3 direction = entityOrigin.subtract(this.center).normalize(); boolean shouldDamageEntity = this.damageCalculator.shouldDamageEntity(this, entity); float knockbackMultiplier = this.damageCalculator.getKnockbackMultiplier(entity); -- float f1 = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : getSeenPercent(this.center, entity); -+ float f1 = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : this.getBlockDensity(this.center, entity); // Paper - Optimize explosions +- float exposure = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : getSeenPercent(this.center, entity); ++ float exposure = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : this.getBlockDensity(this.center, entity); // Paper - Optimize explosions if (shouldDamageEntity) { -- entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f1)); +- entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, exposure)); + // CraftBukkit start + + // Special case ender dragon only give knockback if no damage is cancelled @@ -91,21 +76,21 @@ + // - Damaging EnderDragonPart while forward the damage to EnderDragon + // - Damaging EnderDragon does nothing + // - EnderDragon hitbox always covers the other parts and is therefore always present -+ if (entity instanceof EnderDragonPart) { ++ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragonPart) { + continue; + } + + entity.lastDamageCancelled = false; + -+ if (entity instanceof EnderDragon) { -+ for (EnderDragonPart dragonPart : ((EnderDragon) entity).getSubEntities()) { ++ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon enderDragon) { ++ for (net.minecraft.world.entity.boss.enderdragon.EnderDragonPart dragonPart : enderDragon.getSubEntities()) { + // Calculate damage separately for each EntityComplexPart + if (list.contains(dragonPart)) { -+ dragonPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, dragonPart, f1)); ++ dragonPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, dragonPart, exposure)); + } + } + } else { -+ entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f1)); ++ entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, exposure)); + } + + if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled @@ -114,37 +99,37 @@ + // CraftBukkit end } - double d1 = entity instanceof LivingEntity livingEntity + double knockbackResistance = entity instanceof LivingEntity livingEntity ? livingEntity.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE) : 0.0; -- double d2 = (1.0 - d) * f1 * knockbackMultiplier * (1.0 - d1); -+ double d2 = entity instanceof Player && this.level.paperConfig().environment.disableExplosionKnockback ? 0 : (1.0 - d) * f1 * knockbackMultiplier * (1.0 - d1); // Paper - Vec3 vec32 = vec31.scale(d2); +- double knockbackPower = (1.0 - dist) * exposure * knockbackMultiplier * (1.0 - knockbackResistance); ++ double knockbackPower = entity instanceof Player && this.level.paperConfig().environment.disableExplosionKnockback ? 0 : (1.0 - dist) * exposure * knockbackMultiplier * (1.0 - knockbackResistance); // Paper + Vec3 knockback = direction.scale(knockbackPower); + // CraftBukkit start - Call EntityKnockbackEvent + if (entity instanceof LivingEntity) { + // Paper start - knockback events -+ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.source, this.damageSource.getEntity() != null ? this.damageSource.getEntity() : this.source, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.EXPLOSION, d2, vec32); -+ vec32 = event.isCancelled() ? Vec3.ZERO : org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getKnockback()); ++ io.papermc.paper.event.entity.EntityKnockbackEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.source, this.damageSource.getEntity() != null ? this.damageSource.getEntity() : this.source, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.EXPLOSION, knockbackPower, knockback); ++ knockback = event.isCancelled() ? Vec3.ZERO : org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getKnockback()); + // Paper end - knockback events + } + // CraftBukkit end - entity.push(vec32); - if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile) { + entity.push(knockback); + if (entity.is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile) { projectile.setOwner(this.damageSource.getEntity()); - } else if (entity instanceof Player player && !player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying)) { + } else if (entity instanceof Player player && !player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback - this.hitPlayers.put(player, vec32); + this.hitPlayers.put(player, knockback); } -@@ -214,7 +_,56 @@ - List list = new ArrayList<>(); - Util.shuffle(blocks, this.level.random); +@@ -213,7 +_,56 @@ + List stacks = new ArrayList<>(); + Util.shuffle(targetBlocks, this.level.random); + // CraftBukkit start -+ Location location = CraftLocation.toBukkit(this.center, this.level); ++ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.center, this.level); + List blockList = new ObjectArrayList<>(); -+ for (int i1 = blocks.size() - 1; i1 >= 0; i1--) { -+ org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level, blocks.get(i1)); ++ for (int i1 = targetBlocks.size() - 1; i1 >= 0; i1--) { ++ org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level, targetBlocks.get(i1)); + if (!bblock.getType().isAir()) { + blockList.add(bblock); + } @@ -153,22 +138,22 @@ + List bukkitBlocks; + + if (this.source != null) { -+ org.bukkit.event.entity.EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blockList, this.yield, this.getBlockInteraction()); ++ org.bukkit.event.entity.EntityExplodeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityExplodeEvent(this.source, blockList, this.yield, this.getBlockInteraction()); + this.wasCanceled = event.isCancelled(); + bukkitBlocks = event.blockList(); + this.yield = event.getYield(); + } else { + org.bukkit.block.Block block = location.getBlock(); + org.bukkit.block.BlockState blockState = (this.damageSource.causingBlockSnapshot() != null) ? this.damageSource.causingBlockSnapshot() : block.getState(); -+ org.bukkit.event.block.BlockExplodeEvent event = CraftEventFactory.callBlockExplodeEvent(block, blockState, blockList, this.yield, this.getBlockInteraction()); ++ org.bukkit.event.block.BlockExplodeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockExplodeEvent(block, blockState, blockList, this.yield, this.getBlockInteraction()); + this.wasCanceled = event.isCancelled(); + bukkitBlocks = event.blockList(); + this.yield = event.getYield(); + } + -+ blocks.clear(); ++ targetBlocks.clear(); + for (org.bukkit.block.Block bblock : bukkitBlocks) { -+ blocks.add(((org.bukkit.craftbukkit.block.CraftBlock) bblock).getPosition()); ++ targetBlocks.add(((org.bukkit.craftbukkit.block.CraftBlock) bblock).getPosition()); + } + + if (this.wasCanceled) { @@ -176,42 +161,41 @@ + } + // CraftBukkit end + - for (BlockPos blockPos : blocks) { + for (BlockPos pos : targetBlocks) { + // CraftBukkit start - TNTPrimeEvent -+ BlockState state = this.level.getBlockState(blockPos); ++ BlockState state = this.level.getBlockState(pos); + Block block = state.getBlock(); + if (level.getGameRules().get(GameRules.TNT_EXPLODES) && block instanceof net.minecraft.world.level.block.TntBlock) { + Entity sourceEntity = this.source == null ? null : this.source; + BlockPos sourceBlock = sourceEntity == null ? BlockPos.containing(this.center) : null; -+ if (!CraftEventFactory.callTNTPrimeEvent(this.level, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, sourceEntity, sourceBlock)) { -+ this.level.sendBlockUpdated(blockPos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), state, Block.UPDATE_ALL); // Update the block on the client ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(this.level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, sourceEntity, sourceBlock)) { ++ this.level.sendBlockUpdated(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), state, Block.UPDATE_ALL); // Update the block on the client + continue; + } + } + // CraftBukkit end + - this.level - .getBlockState(blockPos) - .onExplosionHit(this.level, blockPos, this, (itemStack, blockPos1) -> addOrAppendStack(list, itemStack, blockPos1)); -@@ -228,7 +_,11 @@ - private void createFire(List blocks) { - for (BlockPos blockPos : blocks) { - if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(blockPos).isAir() && this.level.getBlockState(blockPos.below()).isSolidRender()) { -- this.level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level, blockPos)); + this.level.getBlockState(pos).onExplosionHit(this.level, pos, this, (stackx, position) -> addOrAppendStack(stacks, stackx, position)); + } + +@@ -225,7 +_,11 @@ + private void createFire(final List targetBlocks) { + for (BlockPos pos : targetBlocks) { + if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(pos).isAir() && this.level.getBlockState(pos.below()).isSolidRender()) { +- this.level.setBlockAndUpdate(pos, BaseFireBlock.getState(this.level, pos)); + // CraftBukkit start - Ignition by explosion -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockPos, this).isCancelled()) { -+ this.level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level, blockPos)); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, pos, this).isCancelled()) { ++ this.level.setBlockAndUpdate(pos, BaseFireBlock.getState(this.level, pos)); + } + // CraftBukkit end } } } -@@ -326,4 +_,86 @@ +@@ -323,4 +_,85 @@ } } } + -+ + // Paper start - Optimize explosions + private float getBlockDensity(Vec3 vec3d, Entity entity) { + if (!this.level.paperConfig().environment.optimizeExplosions) { @@ -291,5 +275,5 @@ + return result; + } + } -+ // Paper end ++ // Paper end - Optimize explosions } diff --git a/paper-server/patches/sources/net/minecraft/world/level/ServerLevelAccessor.java.patch b/paper-server/patches/sources/net/minecraft/world/level/ServerLevelAccessor.java.patch index 0f1af218f263..5183763f07cb 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/ServerLevelAccessor.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/ServerLevelAccessor.java.patch @@ -3,7 +3,7 @@ @@ -11,6 +_,17 @@ DifficultyInstance getCurrentDifficultyAt(BlockPos pos); - default void addFreshEntityWithPassengers(Entity entity) { + default void addFreshEntityWithPassengers(final Entity entity) { - entity.getSelfAndPassengers().forEach(this::addFreshEntity); - } + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/level/StructureManager.java.patch b/paper-server/patches/sources/net/minecraft/world/level/StructureManager.java.patch index 690024da9c8e..45e3bbb678d0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/StructureManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/StructureManager.java.patch @@ -3,47 +3,47 @@ @@ -48,7 +_,13 @@ } - public List startsForStructure(ChunkPos chunkPos, Predicate structurePredicate) { -- Map allReferences = this.level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); + public List startsForStructure(final ChunkPos pos, final Predicate matcher) { +- Map allReferences = this.level.getChunk(pos.x(), pos.z(), ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); + // Paper start - Fix swamp hut cat generation deadlock -+ return this.startsForStructure(chunkPos, structurePredicate, null); ++ return this.startsForStructure(pos, matcher, null); + } + -+ public List startsForStructure(ChunkPos chunkPos, Predicate structurePredicate, @Nullable ServerLevelAccessor levelAccessor) { -+ Map allReferences = (levelAccessor == null ? this.level : levelAccessor).getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); ++ public List startsForStructure(final ChunkPos pos, final Predicate matcher, final @Nullable ServerLevelAccessor levelAccessor) { ++ Map allReferences = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x(), pos.z(), ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); + // Paper end - Fix swamp hut cat generation deadlock - Builder builder = ImmutableList.builder(); + Builder result = ImmutableList.builder(); for (Entry entry : allReferences.entrySet()) { -@@ -113,14 +_,29 @@ +@@ -111,14 +_,29 @@ } - public StructureStart getStructureWithPieceAt(BlockPos pos, HolderSet structures) { -- return this.getStructureWithPieceAt(pos, structures::contains); -+ // Paper start - Fix swamp hut cat generation deadlock -+ return this.getStructureWithPieceAt(pos, structures, null); + public StructureStart getStructureWithPieceAt(final BlockPos blockPos, final HolderSet structures) { +- return this.getStructureWithPieceAt(blockPos, structures::contains); ++ // Paper start - Fix swamp hut cat generation deadlock ++ return this.getStructureWithPieceAt(blockPos, structures, null); + } -+ public StructureStart getStructureWithPieceAt(BlockPos pos, HolderSet structures, final @Nullable ServerLevelAccessor levelAccessor) { -+ return this.getStructureWithPieceAt(pos, structures::contains, levelAccessor); -+ // Paper end - Fix swamp hut cat generation deadlock ++ public StructureStart getStructureWithPieceAt(final BlockPos blockPos, final HolderSet structures, final @Nullable ServerLevelAccessor levelAccessor) { ++ return this.getStructureWithPieceAt(blockPos, structures::contains, levelAccessor); ++ // Paper end - Fix swamp hut cat generation deadlock } - public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate) { + public StructureStart getStructureWithPieceAt(final BlockPos blockPos, final Predicate> predicate) { + // Paper start - Fix swamp hut cat generation deadlock -+ return this.getStructureWithPieceAt(pos, predicate, null); ++ return this.getStructureWithPieceAt(blockPos, predicate, null); + } + -+ public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey tag, @Nullable ServerLevelAccessor levelAccessor) { -+ return this.getStructureWithPieceAt(pos, structure -> structure.is(tag), levelAccessor); ++ public StructureStart getStructureWithPieceAt(final BlockPos blockPos, final TagKey structureTag, final @Nullable ServerLevelAccessor levelAccessor) { ++ return this.getStructureWithPieceAt(blockPos, structure -> structure.is(structureTag), levelAccessor); + } + -+ public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate, @Nullable ServerLevelAccessor levelAccessor) { ++ public StructureStart getStructureWithPieceAt(final BlockPos blockPos, final Predicate> predicate, final @Nullable ServerLevelAccessor levelAccessor) { + // Paper end - Fix swamp hut cat generation deadlock - Registry registry = this.registryAccess().lookupOrThrow(Registries.STRUCTURE); + Registry structures = this.registryAccess().lookupOrThrow(Registries.STRUCTURE); for (StructureStart structureStart : this.startsForStructure( -- new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false) -+ new ChunkPos(pos), structure -> registry.get(registry.getId(structure)).map(predicate::test).orElse(false), levelAccessor // Paper - Fix swamp hut cat generation deadlock +- ChunkPos.containing(blockPos), s -> structures.get(structures.getId(s)).map(predicate::test).orElse(false) ++ ChunkPos.containing(blockPos), s -> structures.get(structures.getId(s)).map(predicate::test).orElse(false), levelAccessor // Paper - Fix swamp hut cat generation deadlock )) { - if (this.structureHasPieceAt(pos, structureStart)) { + if (this.structureHasPieceAt(blockPos, structureStart)) { return structureStart; diff --git a/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch index 9d1bfb3fb2ca..0ecdaf2a849e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/level/TicketStorage.java +++ b/net/minecraft/world/level/TicketStorage.java -@@ -177,7 +_,7 @@ +@@ -179,7 +_,7 @@ } - private static boolean isTicketSameTypeAndLevel(Ticket first, Ticket second) { -- return second.getType() == first.getType() && second.getTicketLevel() == first.getTicketLevel(); -+ return second.getType() == first.getType() && second.getTicketLevel() == first.getTicketLevel() && java.util.Objects.equals(second.getIdentifier(), first.getIdentifier()); // Paper - add identifier + private static boolean isTicketSameTypeAndLevel(final Ticket ticket, final Ticket t) { +- return t.getType() == ticket.getType() && t.getTicketLevel() == ticket.getTicketLevel(); ++ return t.getType() == ticket.getType() && t.getTicketLevel() == ticket.getTicketLevel() && java.util.Objects.equals(t.getIdentifier(), ticket.getIdentifier()); // Paper - add identifier } - public int getTicketLevelAt(long chunkPos, boolean requireSimulation) { -@@ -298,7 +_,7 @@ + public int getTicketLevelAt(final long key, final boolean simulation) { +@@ -300,7 +_,7 @@ } public void deactivateTicketsOnClosing() { @@ -17,8 +17,8 @@ + this.removeTicketIf((ticket, chunkPos) -> ticket.getType() != TicketType.UNKNOWN && ticket.getType() != TicketType.CHUNK_LOAD && ticket.getType() != TicketType.FUTURE_AWAIT, this.deactivatedTickets); } - public void removeTicketIf(TicketStorage.TicketPredicate predicate, @Nullable Long2ObjectOpenHashMap> tickets) { -@@ -408,4 +_,20 @@ + public void removeTicketIf(final TicketStorage.TicketPredicate predicate, final @Nullable Long2ObjectOpenHashMap> removedTickets) { +@@ -410,4 +_,20 @@ public interface TicketPredicate { boolean test(Ticket ticket, long chunkPos); } @@ -26,12 +26,12 @@ + // Paper start + public boolean addPluginRegionTicket(final ChunkPos pos, final org.bukkit.plugin.Plugin value) { + // Keep inline with force loading -+ return addTicket(pos.toLong(), new Ticket(TicketType.PLUGIN_TICKET, ChunkMap.FORCED_TICKET_LEVEL, value)); ++ return addTicket(pos.pack(), new Ticket(TicketType.PLUGIN_TICKET, ChunkMap.FORCED_TICKET_LEVEL, value)); + } + + public boolean removePluginRegionTicket(final ChunkPos pos, final org.bukkit.plugin.Plugin value) { + // Keep inline with force loading -+ return removeTicket(pos.toLong(), new Ticket(TicketType.PLUGIN_TICKET, ChunkMap.FORCED_TICKET_LEVEL, value)); ++ return removeTicket(pos.pack(), new Ticket(TicketType.PLUGIN_TICKET, ChunkMap.FORCED_TICKET_LEVEL, value)); + } + + public void removeAllPluginRegionTickets(TicketType ticketType, int ticketLevel, org.bukkit.plugin.Plugin ticketIdentifier) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/biome/MobSpawnSettings.java.patch b/paper-server/patches/sources/net/minecraft/world/level/biome/MobSpawnSettings.java.patch index 1c762eb3f28b..b9f1404094d7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/biome/MobSpawnSettings.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/biome/MobSpawnSettings.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/biome/MobSpawnSettings.java +++ b/net/minecraft/world/level/biome/MobSpawnSettings.java -@@ -69,9 +_,33 @@ +@@ -67,9 +_,33 @@ } public static class Builder { @@ -28,8 +28,8 @@ + } + } private final Map> spawners = Util.makeEnumMap( -- MobCategory.class, mobCategory -> WeightedList.builder() -+ MobCategory.class, mobCategory -> new MobListBuilder<>() +- MobCategory.class, c -> WeightedList.builder() ++ MobCategory.class, c -> new MobListBuilder<>() ); + // Paper end - Perf: keep track of data in a pair set to give O(1) contains calls private final Map, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.newLinkedHashMap(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCandleBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCandleBlock.java.patch index 45e20e27aabc..792875602be6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCandleBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCandleBlock.java.patch @@ -2,13 +2,13 @@ +++ b/net/minecraft/world/level/block/AbstractCandleBlock.java @@ -44,6 +_,11 @@ @Override - protected void onProjectileHit(Level level, BlockState state, BlockHitResult hit, Projectile projectile) { + protected void onProjectileHit(final Level level, final BlockState state, final BlockHitResult blockHit, final Projectile projectile) { if (!level.isClientSide() && projectile.isOnFire() && this.canBeLit(state)) { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, hit.getBlockPos(), projectile).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, blockHit.getBlockPos(), projectile).isCancelled()) { + return; + } + // CraftBukkit end - setLit(level, state, hit.getBlockPos(), true); + setLit(level, state, blockHit.getBlockPos(), true); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCauldronBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCauldronBlock.java.patch index 84b3f16b693b..aa79ed5f8219 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCauldronBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/AbstractCauldronBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/AbstractCauldronBlock.java +++ b/net/minecraft/world/level/block/AbstractCauldronBlock.java -@@ -57,7 +_,7 @@ - ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult +@@ -63,7 +_,7 @@ + final BlockHitResult hitResult ) { - CauldronInteraction cauldronInteraction = this.interactions.map().get(stack.getItem()); -- return cauldronInteraction.interact(state, level, pos, player, hand, stack); -+ return cauldronInteraction.interact(state, level, pos, player, hand, stack, hitResult.getDirection()); // Paper - pass hit direction + CauldronInteraction behavior = this.interactions.get(itemStack); +- return behavior.interact(state, level, pos, player, hand, itemStack); ++ return behavior.interact(state, level, pos, player, hand, itemStack, hitResult.getDirection()); // Paper - pass hit direction } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch index 881ac03b5221..bb6e8332e912 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/AnvilBlock.java +++ b/net/minecraft/world/level/block/AnvilBlock.java -@@ -57,8 +_,9 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -59,8 +_,9 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BambooSaplingBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BambooSaplingBlock.java.patch index 0d3b02199c7b..ac54e89726fc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BambooSaplingBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BambooSaplingBlock.java.patch @@ -3,7 +3,7 @@ @@ -38,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { - if (random.nextInt(3) == 0 && level.isEmptyBlock(pos.above()) && level.getRawBrightness(pos.above(), 0) >= 9) { + if (random.nextFloat() < (level.spigotConfig.bambooModifier / (100.0F * 3)) && level.isEmptyBlock(pos.above()) && level.getRawBrightness(pos.above(), 0) >= 9) { // Spigot - SPIGOT-7159: Better modifier resolution this.growBamboo(level, pos); @@ -12,8 +12,8 @@ @@ -89,6 +_,6 @@ } - protected void growBamboo(Level level, BlockPos state) { -- level.setBlock(state.above(), Blocks.BAMBOO.defaultBlockState().setValue(BambooStalkBlock.LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, state, state.above(), Blocks.BAMBOO.defaultBlockState().setValue(BambooStalkBlock.LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); // CraftBukkit - BlockSpreadEvent + protected void growBamboo(final Level level, final BlockPos pos) { +- level.setBlock(pos.above(), Blocks.BAMBOO.defaultBlockState().setValue(BambooStalkBlock.LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, pos.above(), Blocks.BAMBOO.defaultBlockState().setValue(BambooStalkBlock.LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); // CraftBukkit - BlockSpreadEvent } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BambooStalkBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BambooStalkBlock.java.patch index 7d3f8ebef722..8f2b6833f266 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BambooStalkBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BambooStalkBlock.java.patch @@ -2,84 +2,85 @@ +++ b/net/minecraft/world/level/block/BambooStalkBlock.java @@ -119,9 +_,9 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (state.getValue(STAGE) == 0) { - if (random.nextInt(3) == 0 && level.isEmptyBlock(pos.above()) && level.getRawBrightness(pos.above(), 0) >= 9) { + if (random.nextFloat() < (level.spigotConfig.bambooModifier / (100.0F * 3)) && level.isEmptyBlock(pos.above()) && level.getRawBrightness(pos.above(), 0) >= 9) { // Spigot - SPIGOT-7159: Better modifier resolution - int i = this.getHeightBelowUpToMax(level, pos) + 1; -- if (i < 16) { -+ if (i < level.paperConfig().maxGrowthHeight.bamboo.max) { // Paper - Configurable cactus/bamboo/reed growth height - this.growBamboo(state, level, pos, random, i); + int height = this.getHeightBelowUpToMax(level, pos) + 1; +- if (height < 16) { ++ if (height < level.paperConfig().maxGrowthHeight.bamboo.max) { // Paper - Configurable cactus/bamboo/reed growth height + this.growBamboo(state, level, pos, random, height); } } -@@ -157,7 +_,7 @@ - public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { - int heightAboveUpToMax = this.getHeightAboveUpToMax(level, pos); - int heightBelowUpToMax = this.getHeightBelowUpToMax(level, pos); -- return heightAboveUpToMax + heightBelowUpToMax + 1 < 16 && level.getBlockState(pos.above(heightAboveUpToMax)).getValue(STAGE) != 1; -+ return heightAboveUpToMax + heightBelowUpToMax + 1 < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max && level.getBlockState(pos.above(heightAboveUpToMax)).getValue(STAGE) != 1; // Paper - Configurable cactus/bamboo/reed growth height - } - - @Override -@@ -175,7 +_,7 @@ - for (int i2 = 0; i2 < i1; i2++) { - BlockPos blockPos = pos.above(heightAboveUpToMax); - BlockState blockState = level.getBlockState(blockPos); -- if (i >= 16 || blockState.getValue(STAGE) == 1 || !level.isEmptyBlock(blockPos.above())) { -+ if (i >= level.paperConfig().maxGrowthHeight.bamboo.max || !blockState.is(Blocks.BAMBOO) || blockState.getValue(BambooStalkBlock.STAGE) == 1 || !level.isEmptyBlock(blockPos.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus/bamboo/reed growth height +@@ -158,7 +_,7 @@ + int heightAbove = this.getHeightAboveUpToMax(level, pos); + int heightBelow = this.getHeightBelowUpToMax(level, pos); + BlockPos growthPos = pos.above(heightAbove + 1); +- return heightAbove + heightBelow + 1 < 16 ++ return heightAbove + heightBelow + 1 < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max // Paper - Configurable cactus/bamboo/reed growth height + && level.getBlockState(pos.above(heightAbove)).getValue(STAGE) != 1 + && level.isInsideBuildHeight(growthPos) + && level.isEmptyBlock(growthPos); +@@ -180,7 +_,7 @@ + BlockPos topPos = pos.above(heightAbove); + BlockState topState = level.getBlockState(topPos); + BlockPos growthPos = topPos.above(); +- if (totalHeight >= 16 || topState.getValue(STAGE) == 1 || !level.isEmptyBlock(growthPos) || level.isOutsideBuildHeight(growthPos)) { ++ if (totalHeight >= level.paperConfig().maxGrowthHeight.bamboo.max || !topState.is(Blocks.BAMBOO) || topState.getValue(STAGE) == 1 || !level.isEmptyBlock(growthPos) || level.isOutsideBuildHeight(growthPos)) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus/bamboo/reed growth height return; } -@@ -190,27 +_,38 @@ - BlockPos blockPos = pos.below(2); - BlockState blockState1 = level.getBlockState(blockPos); - BambooLeaves bambooLeaves = BambooLeaves.NONE; +@@ -195,27 +_,39 @@ + BlockPos twoBelowPos = pos.below(2); + BlockState twoBelowState = level.getBlockState(twoBelowPos); + BambooLeaves leaves = BambooLeaves.NONE; + boolean shouldUpdateOthers = false; // CraftBukkit - if (age >= 1) { - if (!blockState.is(Blocks.BAMBOO) || blockState.getValue(LEAVES) == BambooLeaves.NONE) { - bambooLeaves = BambooLeaves.SMALL; - } else if (blockState.is(Blocks.BAMBOO) && blockState.getValue(LEAVES) != BambooLeaves.NONE) { - bambooLeaves = BambooLeaves.LARGE; - if (blockState1.is(Blocks.BAMBOO)) { -- level.setBlock(pos.below(), blockState.setValue(LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); -- level.setBlock(blockPos, blockState1.setValue(LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); + if (height >= 1) { + if (!belowState.is(Blocks.BAMBOO) || belowState.getValue(LEAVES) == BambooLeaves.NONE) { + leaves = BambooLeaves.SMALL; + } else if (belowState.is(Blocks.BAMBOO) && belowState.getValue(LEAVES) != BambooLeaves.NONE) { + leaves = BambooLeaves.LARGE; + if (twoBelowState.is(Blocks.BAMBOO)) { +- level.setBlock(pos.below(), belowState.setValue(LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); +- level.setBlock(twoBelowPos, twoBelowState.setValue(LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); + // CraftBukkit start - moved down -+ // level.setBlock(pos.below(), blockState.setValue(LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); -+ // level.setBlock(blockPos, blockState1.setValue(LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); ++ // level.setBlock(pos.below(), belowState.setValue(LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); ++ // level.setBlock(twoBelowPos, twoBelowState.setValue(LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); + shouldUpdateOthers = true; + // CraftBukkit end } } } - int i = state.getValue(AGE) != 1 && !blockState1.is(Blocks.BAMBOO) ? 0 : 1; -- int i1 = (age < 11 || !(random.nextFloat() < 0.25F)) && age != 15 ? 0 : 1; -- level.setBlock(pos.above(), this.defaultBlockState().setValue(AGE, i).setValue(LEAVES, bambooLeaves).setValue(STAGE, i1), Block.UPDATE_ALL); -+ int i1 = (age < level.paperConfig().maxGrowthHeight.bamboo.min || random.nextFloat() >= 0.25F) && age != (level.paperConfig().maxGrowthHeight.bamboo.max - 1) ? 0 : 1; // Paper - Configurable cactus/bamboo/reed growth height + int age = state.getValue(AGE) != 1 && !twoBelowState.is(Blocks.BAMBOO) ? 0 : 1; +- int stage = (height < 11 || !(random.nextFloat() < 0.25F)) && height != 15 ? 0 : 1; +- level.setBlock(pos.above(), this.defaultBlockState().setValue(AGE, age).setValue(LEAVES, leaves).setValue(STAGE, stage), Block.UPDATE_ALL); ++ int stage = (height < level.paperConfig().maxGrowthHeight.bamboo.min || !(random.nextFloat() < 0.25F)) && height != (level.paperConfig().maxGrowthHeight.bamboo.max - 1) ? 0 : 1; // Paper - Configurable cactus/bamboo/reed growth height ++ // level.setBlock(pos.above(), this.defaultBlockState().setValue(AGE, age).setValue(LEAVES, leaves).setValue(STAGE, stage), Block.UPDATE_ALL); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, pos.above(), this.defaultBlockState().setValue(AGE, i).setValue(LEAVES, bambooLeaves).setValue(STAGE, i1), Block.UPDATE_ALL)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, pos.above(), this.defaultBlockState().setValue(AGE, age).setValue(LEAVES, leaves).setValue(STAGE, stage), Block.UPDATE_ALL)) { + if (shouldUpdateOthers) { -+ level.setBlock(pos.below(), blockState.setValue(BambooStalkBlock.LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); -+ level.setBlock(blockPos, blockState1.setValue(BambooStalkBlock.LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); ++ level.setBlock(pos.below(), belowState.setValue(LEAVES, BambooLeaves.SMALL), Block.UPDATE_ALL); ++ level.setBlock(twoBelowPos, twoBelowState.setValue(LEAVES, BambooLeaves.NONE), Block.UPDATE_ALL); + } + } + // CraftBukkit end } - protected int getHeightAboveUpToMax(BlockGetter level, BlockPos pos) { - int i = 0; + protected int getHeightAboveUpToMax(final BlockGetter level, final BlockPos pos) { + int height = 0; -- while (i < 16 && level.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO)) { -+ while (i < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max && level.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO)) { // Paper - Configurable cactus/bamboo/reed growth height - i++; +- while (height < 16 && level.getBlockState(pos.above(height + 1)).is(Blocks.BAMBOO)) { ++ while (height < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max && level.getBlockState(pos.above(height + 1)).is(Blocks.BAMBOO)) { // Paper - Configurable cactus/bamboo/reed growth height + height++; } -@@ -220,7 +_,7 @@ - protected int getHeightBelowUpToMax(BlockGetter level, BlockPos pos) { - int i = 0; +@@ -225,7 +_,7 @@ + protected int getHeightBelowUpToMax(final BlockGetter level, final BlockPos pos) { + int height = 0; -- while (i < 16 && level.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO)) { -+ while (i < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max && level.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO)) { // Paper - Configurable cactus/bamboo/reed growth height - i++; +- while (height < 16 && level.getBlockState(pos.below(height + 1)).is(Blocks.BAMBOO)) { ++ while (height < ((Level) level).paperConfig().maxGrowthHeight.bamboo.max && level.getBlockState(pos.below(height + 1)).is(Blocks.BAMBOO)) { // Paper - Configurable cactus/bamboo/reed growth height + height++; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BarrelBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BarrelBlock.java.patch index 23b0b9718c2f..de2dcc6bf900 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BarrelBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BarrelBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/BarrelBlock.java +++ b/net/minecraft/world/level/block/BarrelBlock.java -@@ -41,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -43,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { - if (level instanceof ServerLevel serverLevel && level.getBlockEntity(pos) instanceof BarrelBlockEntity barrelBlockEntity) { - player.openMenu(barrelBlockEntity); + if (level instanceof ServerLevel serverLevel && level.getBlockEntity(pos) instanceof BarrelBlockEntity barrelBlockEntity && player.openMenu(barrelBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch index ad725ef8b45c..051186dfaaaf 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/level/block/BaseFireBlock.java +++ b/net/minecraft/world/level/block/BaseFireBlock.java -@@ -129,12 +_,13 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -136,12 +_,13 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent effectApplier.apply(InsideBlockEffectType.CLEAR_FREEZE); effectApplier.apply(InsideBlockEffectType.FIRE_IGNITE); - effectApplier.runAfter(InsideBlockEffectType.FIRE_IGNITE, entity1 -> entity1.hurt(entity1.level().damageSources().inFire(), this.fireDamage)); + effectApplier.runAfter(InsideBlockEffectType.FIRE_IGNITE, e -> e.hurt(e.level().damageSources().inFire(), this.fireDamage)); } -- public static void fireIgnite(Entity entity) { -+ public static void fireIgnite(Entity entity, BlockPos pos) { // Paper - track position inside effect was triggered on +- public static void fireIgnite(final Entity entity) { ++ public static void fireIgnite(final Entity entity, BlockPos pos) { // Paper - track position inside effect was triggered on if (!entity.fireImmune()) { if (entity.getRemainingFireTicks() < 0) { entity.setRemainingFireTicks(entity.getRemainingFireTicks() + 1); -@@ -144,30 +_,41 @@ +@@ -151,30 +_,41 @@ } if (entity.getRemainingFireTicks() >= 0) { @@ -37,14 +37,14 @@ } @Override -- protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { -+ protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston, net.minecraft.world.item.context.UseOnContext context) { // CraftBukkit - context +- protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { ++ protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston, net.minecraft.world.item.context.UseOnContext context) { // CraftBukkit - context if (!oldState.is(state.getBlock())) { if (inPortalDimension(level)) { - Optional optional = PortalShape.findEmptyPortalShape(level, pos, Direction.Axis.X); - if (optional.isPresent()) { -- optional.get().createPortalBlocks(level); -+ optional.get().createPortalBlocks(level, (context == null) ? null : context.getPlayer()); // CraftBukkit - player + Optional optionalShape = PortalShape.findEmptyPortalShape(level, pos, Direction.Axis.X); + if (optionalShape.isPresent()) { +- optionalShape.get().createPortalBlocks(level); ++ optionalShape.get().createPortalBlocks(level, (context == null) ? null : context.getPlayer()); // CraftBukkit - player return; } } @@ -56,13 +56,13 @@ } } - private static boolean inPortalDimension(Level level) { + private static boolean inPortalDimension(final Level level) { - return level.dimension() == Level.OVERWORLD || level.dimension() == Level.NETHER; + return level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.OVERWORLD || level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER; // CraftBukkit - getTypeKey() } @Override -@@ -212,4 +_,12 @@ +@@ -219,4 +_,12 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BasePressurePlateBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BasePressurePlateBlock.java.patch index 81437c45bd61..6ce4be6b8aa6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BasePressurePlateBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BasePressurePlateBlock.java.patch @@ -1,41 +1,41 @@ --- a/net/minecraft/world/level/block/BasePressurePlateBlock.java +++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java -@@ -82,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -89,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide()) { - int signalForState = this.getSignalForState(state); - if (signalForState == 0) { -@@ -94,6 +_,16 @@ - int signalStrength = this.getSignalStrength(level, pos); - boolean flag = currentSignal > 0; - boolean flag1 = signalStrength > 0; + int signal = this.getSignalForState(state); + if (signal == 0) { +@@ -101,6 +_,16 @@ + int signal = this.getSignalStrength(level, pos); + boolean wasPressed = oldSignal > 0; + boolean isPressed = signal > 0; + + // CraftBukkit start - Interact Pressure Plate -+ if (flag != flag1) { -+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), currentSignal, signalStrength); ++ if (wasPressed != isPressed) { ++ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldSignal, signal); + eventRedstone.callEvent(); + -+ flag1 = eventRedstone.getNewCurrent() > 0; -+ signalStrength = eventRedstone.getNewCurrent(); ++ isPressed = eventRedstone.getNewCurrent() > 0; ++ signal = eventRedstone.getNewCurrent(); + } + // CraftBukkit end - if (currentSignal != signalStrength) { - BlockState blockState = this.setSignalForState(state, signalStrength); - level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); -@@ -142,7 +_,13 @@ + if (oldSignal != signal) { + BlockState newState = this.setSignalForState(state, signal); + level.setBlock(pos, newState, Block.UPDATE_CLIENTS); +@@ -149,7 +_,13 @@ } - protected static int getEntityCount(Level level, AABB box, Class entityClass) { -- return level.getEntitiesOfClass(entityClass, box, EntitySelector.NO_SPECTATORS.and(entity -> !entity.isIgnoringBlockTriggers())).size(); + protected static int getEntityCount(final Level level, final AABB entityDetectionBox, final Class entityClass) { +- return level.getEntitiesOfClass(entityClass, entityDetectionBox, EntitySelector.NO_SPECTATORS.and(e -> !e.isIgnoringBlockTriggers())).size(); + // CraftBukkit start -+ return BasePressurePlateBlock.getEntities(level, box, entityClass).size(); ++ return BasePressurePlateBlock.getEntities(level, entityDetectionBox, entityClass).size(); + } + + protected static java.util.List getEntities(Level level, AABB box, Class entityClass) { -+ return level.getEntitiesOfClass(entityClass, box, EntitySelector.NO_SPECTATORS.and(entity -> !entity.isIgnoringBlockTriggers())); ++ return level.getEntitiesOfClass(entityClass, box, EntitySelector.NO_SPECTATORS.and(e -> !e.isIgnoringBlockTriggers())); + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BeaconBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BeaconBlock.java.patch index 07ff52d43be4..439cead433ab 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BeaconBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BeaconBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/BeaconBlock.java +++ b/net/minecraft/world/level/block/BeaconBlock.java -@@ -45,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { -- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BeaconBlockEntity beaconBlockEntity) { -- player.openMenu(beaconBlockEntity); -+ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BeaconBlockEntity beaconBlockEntity && player.openMenu(beaconBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation +@@ -47,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { +- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BeaconBlockEntity beacon) { +- player.openMenu(beacon); ++ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BeaconBlockEntity beacon && player.openMenu(beacon).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation player.awardStat(Stats.INTERACT_WITH_BEACON); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch index 9b9473adc698..112f8088bfe2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch @@ -6,16 +6,16 @@ BedRule bedRule = level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); - if (bedRule.explodes()) { + if (false && bedRule.explodes()) { // CraftBukkit - moved world and biome check into Player - bedRule.errorMessage().ifPresent(component -> player.displayClientMessage(component, true)); + bedRule.errorMessage().ifPresent(player::sendOverlayMessage); level.removeBlock(pos, false); BlockPos blockPos = pos.relative(state.getValue(FACING).getOpposite()); @@ -103,22 +_,61 @@ - level.explode(null, level.damageSources().badRespawnPointExplosion(center), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK); + level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos), null, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); return InteractionResult.SUCCESS_SERVER; } else if (state.getValue(OCCUPIED)) { + if (bedRule.explodes()) return this.explodeBed(state, level, pos); // Paper - check explode first if (!this.kickVillagerOutOfBed(level, pos)) { - player.displayClientMessage(Component.translatable("block.minecraft.bed.occupied"), true); + player.sendOverlayMessage(Component.translatable("block.minecraft.bed.occupied")); } return InteractionResult.SUCCESS_SERVER; @@ -24,14 +24,14 @@ + final BlockState finalBlockState = state; + final BlockPos finalBlockPos = pos; + // CraftBukkit end - player.startSleepInBed(pos).ifLeft(bedSleepingProblem -> { -- if (bedSleepingProblem.message() != null) { + player.startSleepInBed(pos).ifLeft(problem -> { +- if (problem.message() != null) { + // Paper start - PlayerBedFailEnterEvent -+ if (false && bedSleepingProblem.message() != null) { // Moved down - player.displayClientMessage(bedSleepingProblem.message(), true); ++ if (false && problem.message() != null) { // Moved down + player.sendOverlayMessage(problem.message()); } -+ if (bedSleepingProblem != null) { -+ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedFailEnterEvent(player, finalBlockPos, bedSleepingProblem); ++ if (problem != null) { ++ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedFailEnterEvent(player, finalBlockPos, problem); + if (event.isCancelled()) { + return; + } @@ -44,7 +44,7 @@ + // Paper start - PlayerBedFailEnterEvent + final net.kyori.adventure.text.Component message = event.getMessage(); + if (message != null) { -+ player.displayClientMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), true); ++ player.sendOverlayMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); + } + } + // Paper end - PlayerBedFailEnterEvent @@ -69,13 +69,13 @@ + } + // CraftBukkit end + - private boolean kickVillagerOutOfBed(Level level, BlockPos pos) { - List entitiesOfClass = level.getEntitiesOfClass(Villager.class, new AABB(pos), LivingEntity::isSleeping); - if (entitiesOfClass.isEmpty()) { -@@ -296,6 +_,11 @@ + private boolean kickVillagerOutOfBed(final Level level, final BlockPos pos) { + List villagers = level.getEntitiesOfClass(Villager.class, new AABB(pos), LivingEntity::isSleeping); + if (villagers.isEmpty()) { +@@ -298,6 +_,11 @@ if (!level.isClientSide()) { - BlockPos blockPos = pos.relative(state.getValue(FACING)); - level.setBlock(blockPos, state.setValue(PART, BedPart.HEAD), Block.UPDATE_ALL); + BlockPos otherPos = pos.relative(state.getValue(FACING)); + level.setBlock(otherPos, state.setValue(PART, BedPart.HEAD), Block.UPDATE_ALL); + // CraftBukkit start - SPIGOT-7315: Don't updated if we capture block states + if (level.captureBlockStates) { + return; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BeehiveBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BeehiveBlock.java.patch index 3dfcabb0c0a9..4173f2362fd8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BeehiveBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BeehiveBlock.java.patch @@ -1,61 +1,61 @@ --- a/net/minecraft/world/level/block/BeehiveBlock.java +++ b/net/minecraft/world/level/block/BeehiveBlock.java -@@ -87,8 +_,8 @@ - } - - @Override -- public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) { -- super.playerDestroy(level, player, pos, state, blockEntity, stack); -+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion +@@ -94,8 +_,9 @@ + final BlockState state, + final @Nullable BlockEntity blockEntity, + final ItemStack destroyedWith ++ , boolean includeDrops, boolean dropExp // Paper - fix drops not preventing stats/food exhaustion + ) { +- super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith); ++ super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion if (!level.isClientSide() && blockEntity instanceof BeehiveBlockEntity beehiveBlockEntity) { - if (!EnchantmentHelper.hasTag(stack, EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING)) { + if (!EnchantmentHelper.hasTag(destroyedWith, EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING)) { beehiveBlockEntity.emptyAllLivingFromHive(player, state, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); -@@ -96,7 +_,7 @@ +@@ -103,7 +_,7 @@ this.angerNearbyBees(level, pos); } -- CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer)player, state, stack, beehiveBlockEntity.getOccupantCount()); -+ // CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer)player, state, stack, beehiveBlockEntity.getOccupantCount()); // Paper - Trigger bee_nest_destroyed trigger in the correct place; moved until after items are dropped +- CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer)player, state, destroyedWith, beehiveBlockEntity.getOccupantCount()); ++ // CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer)player, state, destroyedWith, beehiveBlockEntity.getOccupantCount()); // Paper - Trigger bee_nest_destroyed trigger in the correct place; moved until after items are dropped } } -@@ -118,7 +_,7 @@ - for (Bee bee : entitiesOfClass) { +@@ -127,7 +_,7 @@ + for (Bee bee : beesToAnger) { if (bee.getTarget() == null) { - Player player = Util.getRandom(entitiesOfClass1, level.random); -- bee.setTarget(player); -+ bee.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit + Player angerTarget = Util.getRandom(playersToBeAngryAt, level.getRandom()); +- bee.setTarget(angerTarget); ++ bee.setTarget(angerTarget, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit } } } -@@ -128,7 +_,7 @@ - ServerLevel level, ItemStack stack, BlockState state, @Nullable BlockEntity blockEntity, @Nullable Entity entity, BlockPos pos +@@ -142,7 +_,7 @@ + final BlockPos pos ) { dropFromBlockInteractLootTable( -- level, BuiltInLootTables.HARVEST_BEEHIVE, state, blockEntity, stack, entity, (serverLevel, itemStack) -> popResource(serverLevel, pos, itemStack) -+ level, BuiltInLootTables.HARVEST_BEEHIVE, state, blockEntity, stack, entity, (serverLevel, itemStack) -> popResource(serverLevel, pos, itemStack) // Paper - diff on change - copied below +- level, BuiltInLootTables.HARVEST_BEEHIVE, blockState, blockEntity, tool, entity, (serverLevel, stack) -> popResource(serverLevel, pos, stack) ++ level, BuiltInLootTables.HARVEST_BEEHIVE, blockState, blockEntity, tool, entity, (serverLevel, stack) -> popResource(serverLevel, pos, stack) // Paper - diff on change - copied below ); } -@@ -141,7 +_,19 @@ - if (honeyLevelValue >= 5) { - Item item = stack.getItem(); - if (level instanceof ServerLevel serverLevel && stack.is(Items.SHEARS)) { -- dropHoneycomb(serverLevel, stack, state, level.getBlockEntity(pos), player, pos); +@@ -161,7 +_,19 @@ + if (honeyLevel >= 5) { + Item item = itemStack.getItem(); + if (level instanceof ServerLevel serverLevel && itemStack.is(Items.SHEARS)) { +- dropHoneycomb(serverLevel, itemStack, state, level.getBlockEntity(pos), player, pos); + // Paper start - Add PlayerShearBlockEvent + List drops = new java.util.ArrayList<>(); + dropFromBlockInteractLootTable( -+ serverLevel, BuiltInLootTables.HARVEST_BEEHIVE, state, level.getBlockEntity(pos), stack, player, (serverLevel1, itemStack) -> drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack)) ++ serverLevel, BuiltInLootTables.HARVEST_BEEHIVE, state, level.getBlockEntity(pos), itemStack, player, (_, stack) -> drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)) + ); -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), drops); ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), drops); + if (!event.callEvent()) { + return InteractionResult.PASS; + } -+ for (org.bukkit.inventory.ItemStack itemStack : event.getDrops()) { -+ popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemStack)); ++ for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { ++ popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(stack)); + } + // Paper end - Add PlayerShearBlockEvent level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BEEHIVE_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F); - stack.hurtAndBreak(1, player, hand.asEquipmentSlot()); - flag = true; + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); + hiveEmptied = true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BellBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BellBlock.java.patch index 2a870fa798e5..9632592e47d2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BellBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BellBlock.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/BellBlock.java +++ b/net/minecraft/world/level/block/BellBlock.java -@@ -137,6 +_,11 @@ +@@ -143,6 +_,11 @@ direction = level.getBlockState(pos).getValue(FACING); } + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBellRingEvent(level, pos, direction, entity)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBellRingEvent(level, pos, direction, ringingEntity)) { + return false; + } + // CraftBukkit end ((BellBlockEntity)blockEntity).onHit(direction); level.playSound(null, pos, SoundEvents.BELL_BLOCK, SoundSource.BLOCKS, 2.0F, 1.0F); - level.gameEvent(entity, GameEvent.BLOCK_CHANGE, pos); + level.gameEvent(ringingEntity, GameEvent.BLOCK_CHANGE, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch index c1d513fdc879..cdec491e2988 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/level/block/BigDripleafBlock.java +++ b/net/minecraft/world/level/block/BigDripleafBlock.java -@@ -126,7 +_,7 @@ +@@ -127,7 +_,7 @@ @Override - protected void onProjectileHit(Level level, BlockState state, BlockHitResult hit, Projectile projectile) { -- this.setTiltAndScheduleTick(state, level, hit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN); -+ this.setTiltAndScheduleTick(state, level, hit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN, projectile); // CraftBukkit + protected void onProjectileHit(final Level level, final BlockState state, final BlockHitResult blockHit, final Projectile projectile) { +- this.setTiltAndScheduleTick(state, level, blockHit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN); ++ this.setTiltAndScheduleTick(state, level, blockHit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN, projectile); // CraftBukkit } @Override -@@ -189,9 +_,23 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -195,9 +_,23 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide()) { if (state.getValue(TILT) == Tilt.NONE && canEntityTilt(pos, entity) && !level.hasNeighborSignal(pos)) { @@ -34,7 +34,7 @@ } } } -@@ -203,9 +_,9 @@ +@@ -209,9 +_,9 @@ } else { Tilt tilt = state.getValue(TILT); if (tilt == Tilt.UNSTABLE) { @@ -46,13 +46,13 @@ } else if (tilt == Tilt.FULL) { resetTilt(state, level, pos); } -@@ -228,8 +_,11 @@ +@@ -236,8 +_,11 @@ return entity.onGround() && entity.position().y > pos.getY() + 0.6875F; } -- private void setTiltAndScheduleTick(BlockState state, Level level, BlockPos pos, Tilt tilt, @Nullable SoundEvent sound) { +- private void setTiltAndScheduleTick(final BlockState state, final Level level, final BlockPos pos, final Tilt tilt, final @Nullable SoundEvent sound) { - setTilt(state, level, pos, tilt); -+ private void setTiltAndScheduleTick(BlockState state, Level level, BlockPos pos, Tilt tilt, @Nullable SoundEvent sound, @Nullable Entity entity) { ++ private void setTiltAndScheduleTick(final BlockState state, final Level level, final BlockPos pos, final Tilt tilt, final @Nullable SoundEvent sound, @Nullable Entity entity) { + if (!setTilt(state, level, pos, tilt, entity)) { + return; + } @@ -60,10 +60,10 @@ if (sound != null) { playTiltSound(level, pos, sound); } -@@ -241,18 +_,26 @@ +@@ -249,18 +_,26 @@ } - private static void resetTilt(BlockState state, Level level, BlockPos pos) { + private static void resetTilt(final BlockState state, final Level level, final BlockPos pos) { - setTilt(state, level, pos, Tilt.NONE); + setTilt(state, level, pos, Tilt.NONE, null); // CraftBukkit if (state.getValue(TILT) != Tilt.NONE) { @@ -71,18 +71,18 @@ } } -- private static void setTilt(BlockState state, Level level, BlockPos pos, Tilt tilt) { +- private static void setTilt(final BlockState state, final Level level, final BlockPos pos, final Tilt tilt) { + // CraftBukkit start -+ private static boolean setTilt(BlockState state, Level level, BlockPos pos, Tilt tilt, @Nullable Entity entity) { ++ private static boolean setTilt(final BlockState state, final Level level, final BlockPos pos, final Tilt tilt, @Nullable Entity entity) { + if (entity != null) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.setValue(BigDripleafBlock.TILT, tilt))) { + return false; + } + } + // CraftBukkit end - Tilt tilt1 = state.getValue(TILT); + Tilt previousTilt = state.getValue(TILT); level.setBlock(pos, state.setValue(TILT, tilt), Block.UPDATE_CLIENTS); - if (tilt.causesVibration() && tilt != tilt1) { + if (tilt.causesVibration() && tilt != previousTilt) { level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos); } + return true; // CraftBukkit diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BlastFurnaceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BlastFurnaceBlock.java.patch index 26f43d832a90..bb2f89f0f519 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BlastFurnaceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BlastFurnaceBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/BlastFurnaceBlock.java @@ -44,8 +_,7 @@ @Override - protected void openContainer(Level level, BlockPos pos, Player player) { + protected void openContainer(final Level level, final BlockPos pos, final Player player) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof BlastFurnaceBlockEntity) { - player.openMenu((MenuProvider)blockEntity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch index ed028c654c30..c2808c1ed09f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/Block.java +++ b/net/minecraft/world/level/block/Block.java -@@ -88,29 +_,46 @@ +@@ -89,29 +_,46 @@ return !Shapes.joinIsNotEmpty(Shapes.block(), shape, BooleanOp.NOT_SAME); } }); @@ -65,19 +65,19 @@ private @Nullable Item item; private static final int CACHE_SIZE = 256; private static final ThreadLocal> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> { -@@ -366,6 +_,27 @@ - return state.getDrops(builder); +@@ -382,6 +_,27 @@ + return state.getDrops(params); } + // Paper start - Add BlockBreakBlockEvent -+ public static boolean dropResources(BlockState state, LevelAccessor levelAccessor, BlockPos pos, @Nullable BlockEntity blockEntity, BlockPos source) { -+ if (levelAccessor instanceof ServerLevel serverLevel) { ++ public static boolean dropResources(final BlockState state, final Level level, final BlockPos pos, final @Nullable BlockEntity blockEntity, final BlockPos source) { ++ if (level instanceof ServerLevel serverLevel) { + List items = new java.util.ArrayList<>(); + for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { + items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); + } + Block block = state.getBlock(); // Paper - Properly handle xp dropping -+ io.papermc.paper.event.block.BlockBreakBlockEvent event = new io.papermc.paper.event.block.BlockBreakBlockEvent(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, pos), org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, source), items); ++ io.papermc.paper.event.block.BlockBreakBlockEvent event = new io.papermc.paper.event.block.BlockBreakBlockEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.block.CraftBlock.at(level, source), items); + event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping + event.callEvent(); + for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { @@ -90,41 +90,51 @@ + } + // Paper end - Add BlockBreakBlockEvent + - public static void dropResources(BlockState state, Level level, BlockPos pos) { - if (level instanceof ServerLevel) { - getDrops(state, (ServerLevel)level, pos, null).forEach(stack -> popResource(level, pos, stack)); -@@ -381,9 +_,14 @@ + public static void dropResources(final BlockState state, final Level level, final BlockPos pos) { + if (level instanceof ServerLevel serverLevel) { + getDrops(state, serverLevel, pos, null).forEach(stack -> popResource(level, pos, stack)); +@@ -396,6 +_,12 @@ + } } - public static void dropResources(BlockState state, Level level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { -+ // Paper start - Properly handle xp dropping -+ dropResources(state, level, pos, blockEntity, entity, tool, true); ++ // Paper start - Properly handle xp dropping ++ public static void dropResources(final BlockState state, final Level level, final BlockPos pos, final @Nullable BlockEntity blockEntity, final @Nullable Entity breaker, final ItemStack tool) { ++ dropResources(state, level, pos, blockEntity, breaker, tool, true); + } -+ public static void dropResources(BlockState state, Level level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) { -+ // Paper end - Properly handle xp dropping - if (level instanceof ServerLevel) { - getDrops(state, (ServerLevel)level, pos, blockEntity, entity, tool).forEach(stack -> popResource(level, pos, stack)); -- state.spawnAfterBreak((ServerLevel)level, pos, tool, true); -+ state.spawnAfterBreak((ServerLevel)level, pos, tool, dropExperience); // Paper - Properly handle xp dropping ++ // Paper end - Properly handle xp dropping ++ + public static void dropResources( + final BlockState state, + final Level level, +@@ -403,10 +_,11 @@ + final @Nullable BlockEntity blockEntity, + final @Nullable Entity breaker, + final ItemStack tool ++ , final boolean dropExperience // Paper - Properly handle xp dropping + ) { + if (level instanceof ServerLevel serverLevel) { + getDrops(state, serverLevel, pos, blockEntity, breaker, tool).forEach(stack -> popResource(level, pos, stack)); +- state.spawnAfterBreak(serverLevel, pos, tool, true); ++ state.spawnAfterBreak(serverLevel, pos, tool, dropExperience); // Paper - Properly handle xp dropping } } -@@ -414,13 +_,25 @@ - if (level instanceof ServerLevel serverLevel && !stack.isEmpty() && serverLevel.getGameRules().get(GameRules.BLOCK_DROPS)) { - ItemEntity itemEntity = itemEntitySupplier.get(); - itemEntity.setDefaultPickUpDelay(); -- level.addFreshEntity(itemEntity); +@@ -439,13 +_,25 @@ + if (level instanceof ServerLevel serverLevel && !itemStack.isEmpty() && serverLevel.getGameRules().get(GameRules.BLOCK_DROPS)) { + ItemEntity entity = entityFactory.get(); + entity.setDefaultPickUpDelay(); +- level.addFreshEntity(entity); + // CraftBukkit start + if (level.captureDrops != null) { -+ level.captureDrops.add(itemEntity); ++ level.captureDrops.add(entity); + } else { -+ level.addFreshEntity(itemEntity); ++ level.addFreshEntity(entity); + } + // CraftBukkit end } } - public void popExperience(ServerLevel level, BlockPos pos, int amount) { + public void popExperience(final ServerLevel level, final BlockPos pos, final int amount) { + // Paper start - add entity parameter + popExperience(level, pos, amount, null); + } @@ -137,53 +147,61 @@ } } -@@ -438,10 +_,19 @@ +@@ -463,6 +_,13 @@ return this.defaultBlockState(); } -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - fix drops not preventing stats/food exhaustion - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { -+ // Paper start - fix drops not preventing stats/food exhaustion -+ this.playerDestroy(level, player, pos, state, blockEntity, tool, true, true); ++ // Paper start - fix drops not preventing stats/food exhaustion ++ @Deprecated @io.papermc.paper.annotation.DoNotUse ++ public void playerDestroy(final Level level, final Player player, final BlockPos pos, final BlockState state, final @Nullable BlockEntity blockEntity, final ItemStack destroyedWith) { ++ playerDestroy(level, player, pos, state, blockEntity, destroyedWith, true, true); + } ++ // Paper end - fix drops not preventing stats/food exhaustion + -+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { -+ // Paper end - fix drops not preventing stats/food exhaustion + public void playerDestroy( + final Level level, + final Player player, +@@ -470,10 +_,13 @@ + final BlockState state, + final @Nullable BlockEntity blockEntity, + final ItemStack destroyedWith ++ , final boolean includeDrops, final boolean dropExp // Paper - fix drops not preventing stats/food exhaustion + ) { player.awardStat(Stats.BLOCK_MINED.get(this)); - player.causeFoodExhaustion(0.005F); -- dropResources(state, level, pos, blockEntity, player, tool); +- dropResources(state, level, pos, blockEntity, player, destroyedWith); + player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent + if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion -+ Block.dropResources(state, level, pos, blockEntity, player, tool, dropExp); // Paper - Properly handle xp dropping ++ dropResources(state, level, pos, blockEntity, player, destroyedWith, dropExp); // Paper - Properly handle xp dropping + } // Paper - fix drops not preventing stats/food exhaustion } - public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { -@@ -580,12 +_,20 @@ + public void setPlacedBy(final Level level, final BlockPos pos, final BlockState state, final @Nullable LivingEntity by, final ItemStack itemStack) { +@@ -613,12 +_,20 @@ return this.builtInRegistryHolder; } -- protected void tryDropExperience(ServerLevel level, BlockPos pos, ItemStack heldItem, IntProvider amount) { -+ protected int tryDropExperience(ServerLevel level, BlockPos pos, ItemStack heldItem, IntProvider amount) { // CraftBukkit - int i = EnchantmentHelper.processBlockExperience(level, heldItem, amount.sample(level.getRandom())); - if (i > 0) { -- this.popExperience(level, pos, i); +- protected void tryDropExperience(final ServerLevel level, final BlockPos pos, final ItemStack tool, final IntProvider xpRange) { ++ protected int tryDropExperience(final ServerLevel level, final BlockPos pos, final ItemStack tool, final IntProvider xpRange) { // CraftBukkit + int experience = EnchantmentHelper.processBlockExperience(level, tool, xpRange.sample(level.getRandom())); + if (experience > 0) { +- this.popExperience(level, pos, experience); + // CraftBukkit start -+ //this.popExperience(level, pos, i); -+ return i; ++ // this.popExperience(level, pos, experience); ++ return experience; } - } + return 0; + } + -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + return 0; + } + // CraftBukkit end - record ShapePairKey(VoxelShape first, VoxelShape second) { + private record ShapePairKey(VoxelShape first, VoxelShape second) { @Override -@@ -601,6 +_,7 @@ +@@ -634,6 +_,7 @@ @Retention(RetentionPolicy.CLASS) @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE_USE}) diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BrewingStandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BrewingStandBlock.java.patch index f2dadd1ca3a2..0b1eadfd9045 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BrewingStandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BrewingStandBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/BrewingStandBlock.java +++ b/net/minecraft/world/level/block/BrewingStandBlock.java -@@ -63,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -65,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { - if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BrewingStandBlockEntity brewingStandBlockEntity) { - player.openMenu(brewingStandBlockEntity); + if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BrewingStandBlockEntity brewingStandBlockEntity && player.openMenu(brewingStandBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch index e111ecb76ce9..ff83d1baf3fc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/level/block/BubbleColumnBlock.java +++ b/net/minecraft/world/level/block/BubbleColumnBlock.java -@@ -49,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -58,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (pastEdges) { - BlockState blockState = level.getBlockState(pos.above()); - boolean flag = blockState.getCollisionShape(level, pos).isEmpty() && blockState.getFluidState().isEmpty(); + if (isPrecise) { + BlockState stateAbove = level.getBlockState(pos.above()); + boolean nothingAbove = stateAbove.getCollisionShape(level, pos).isEmpty() && stateAbove.getFluidState().isEmpty(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BuddingAmethystBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BuddingAmethystBlock.java.patch index 5e5a9712ddef..5a9e22a2e0be 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BuddingAmethystBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BuddingAmethystBlock.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/level/block/BuddingAmethystBlock.java +++ b/net/minecraft/world/level/block/BuddingAmethystBlock.java @@ -44,7 +_,13 @@ - BlockState blockState1 = block.defaultBlockState() - .setValue(AmethystClusterBlock.FACING, direction) - .setValue(AmethystClusterBlock.WATERLOGGED, blockState.getFluidState().getType() == Fluids.WATER); -- level.setBlockAndUpdate(blockPos, blockState1); + BlockState targetState = nextStage.defaultBlockState() + .setValue(AmethystClusterBlock.FACING, growDirection) + .setValue(AmethystClusterBlock.WATERLOGGED, relativeState.getFluidState().is(Fluids.WATER)); +- level.setBlockAndUpdate(growPos, targetState); + // Paper start - Have Amethyst throw both spread and grow events -+ if (block == Blocks.SMALL_AMETHYST_BUD) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState1, Block.UPDATE_ALL); // CraftBukkit ++ if (nextStage == Blocks.SMALL_AMETHYST_BUD) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, growPos, targetState, Block.UPDATE_ALL); // CraftBukkit + } else { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockPos, blockState1, Block.UPDATE_ALL); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, growPos, targetState, Block.UPDATE_ALL); + } + // Paper end - Have Amethyst throw both spread and grow events } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch index 245dc1efd101..23bf6d6c19b1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/ButtonBlock.java +++ b/net/minecraft/world/level/block/ButtonBlock.java -@@ -89,6 +_,19 @@ +@@ -91,6 +_,19 @@ if (state.getValue(POWERED)) { return InteractionResult.CONSUME; } else { @@ -20,22 +20,22 @@ this.press(state, level, pos, player); return InteractionResult.SUCCESS; } -@@ -150,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -161,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide() && this.type.canButtonBeActivatedByArrows() && !state.getValue(POWERED)) { this.checkPressed(state, level, pos); } -@@ -161,7 +_,31 @@ +@@ -172,7 +_,31 @@ : null; - boolean flag = abstractArrow != null; - boolean poweredValue = state.getValue(POWERED); + boolean shouldBePressed = firstArrow != null; + boolean wasPressed = state.getValue(POWERED); + // CraftBukkit start - Call interact event when arrows turn on wooden buttons -+ if (poweredValue != flag && flag) { ++ if (wasPressed != shouldBePressed && shouldBePressed) { + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(abstractArrow.getBukkitEntity(), block); ++ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(firstArrow.getBukkitEntity(), block); + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { @@ -43,9 +43,9 @@ + } + } + // CraftBukkit end - if (flag != poweredValue) { + if (shouldBePressed != wasPressed) { + // CraftBukkit start -+ boolean powered = poweredValue; ++ boolean powered = wasPressed; + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + int old = (powered) ? 15 : 0; + int current = (!powered) ? 15 : 0; @@ -53,10 +53,10 @@ + org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, old, current); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); + -+ if ((flag && eventRedstone.getNewCurrent() <= 0) || (!flag && eventRedstone.getNewCurrent() > 0)) { ++ if ((shouldBePressed && eventRedstone.getNewCurrent() <= 0) || (!shouldBePressed && eventRedstone.getNewCurrent() > 0)) { + return; + } + // CraftBukkit end - level.setBlock(pos, state.setValue(POWERED, flag), Block.UPDATE_ALL); + level.setBlock(pos, state.setValue(POWERED, shouldBePressed), Block.UPDATE_ALL); this.updateNeighbours(state, level, pos); - this.playSound(null, level, pos, flag); + this.playSound(null, level, pos, shouldBePressed); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch index 1aa3214d37bb..7aba4167643a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch @@ -1,38 +1,33 @@ --- a/net/minecraft/world/level/block/CactusBlock.java +++ b/net/minecraft/world/level/block/CactusBlock.java -@@ -58,18 +_,22 @@ - int ageValue = state.getValue(AGE); +@@ -58,18 +_,18 @@ + int age = state.getValue(AGE); - while (level.getBlockState(pos.below(i)).is(this)) { -- if (++i == 3 && ageValue == 15) { -+ if (++i == level.paperConfig().maxGrowthHeight.cactus && ageValue == 15) { // Paper - Configurable cactus/bamboo/reed growth height + while (level.getBlockState(pos.below(height)).is(this)) { +- if (++height == 3 && age == 15) { ++ if (++height == level.paperConfig().maxGrowthHeight.cactus && age == 15) { // Paper - Configurable cactus/bamboo/reed growth height return; } } - if (ageValue == 8 && this.canSurvive(this.defaultBlockState(), level, pos.above())) { -- double d = i >= 3 ? 0.25 : 0.1; -+ double d = i >= level.paperConfig().maxGrowthHeight.cactus ? 0.25 : 0.1; // Paper - Configurable cactus/bamboo/reed growth height - if (random.nextDouble() <= d) { -- level.setBlockAndUpdate(blockPos, Blocks.CACTUS_FLOWER.defaultBlockState()); -- } -- } else if (ageValue == 15 && i < 3) { -- level.setBlockAndUpdate(blockPos, this.defaultBlockState()); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockPos, Blocks.CACTUS_FLOWER.defaultBlockState(), Block.UPDATE_ALL); -+ } -+ } else if (ageValue == 15 && i < level.paperConfig().maxGrowthHeight.cactus) { // Paper - Configurable cactus/bamboo/reed growth height -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockPos, this.defaultBlockState(), Block.UPDATE_ALL)) { -+ return; -+ } -+ // Paper end - BlockState blockState = state.setValue(AGE, 0); - level.setBlock(pos, blockState, Block.UPDATE_NONE); - level.neighborChanged(blockState, blockPos, this, null, false); -@@ -124,7 +_,8 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { + if (age == 8 && this.canSurvive(this.defaultBlockState(), level, pos.above())) { +- double chanceToGrowFlower = height >= 3 ? 0.25 : 0.1; ++ double chanceToGrowFlower = height >= level.paperConfig().maxGrowthHeight.cactus ? 0.25 : 0.1; // Paper - Configurable cactus/bamboo/reed growth height + if (random.nextDouble() <= chanceToGrowFlower) { +- level.setBlockAndUpdate(above, Blocks.CACTUS_FLOWER.defaultBlockState()); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, above, Blocks.CACTUS_FLOWER.defaultBlockState(), Block.UPDATE_ALL); // Paper - block grow event + } +- } else if (age == 15 && height < 3) { +- level.setBlockAndUpdate(above, this.defaultBlockState()); ++ } else if (age == 15 && height < level.paperConfig().maxGrowthHeight.cactus) { // Paper - Configurable cactus/bamboo/reed growth height ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, above, this.defaultBlockState(), Block.UPDATE_ALL)) return; // Paper - block grow event + BlockState aboveBlock = state.setValue(AGE, 0); + level.setBlock(pos, aboveBlock, Block.UPDATE_NONE); + level.neighborChanged(aboveBlock, above, this, null, false); +@@ -131,7 +_,8 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { - entity.hurt(level.damageSources().cactus(), 1.0F); + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + entity.hurt(level.damageSources().cactus().eventBlockDamager(level, pos), 1.0F); // CraftBukkit diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch index c0319559ed1e..44157946d3de 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch @@ -1,25 +1,25 @@ --- a/net/minecraft/world/level/block/CakeBlock.java +++ b/net/minecraft/world/level/block/CakeBlock.java -@@ -57,6 +_,12 @@ +@@ -63,6 +_,12 @@ ) { - Item item = stack.getItem(); - if (stack.is(ItemTags.CANDLES) && state.getValue(BITES) == 0 && Block.byItem(item) instanceof CandleBlock candleBlock) { + Item item = itemStack.getItem(); + if (itemStack.is(ItemTags.CANDLES) && state.getValue(BITES) == 0 && Block.byItem(item) instanceof CandleBlock candleBlock) { + // Paper start - call change block event + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleBlock))) { + player.containerMenu.forceHeldSlot(hand); // update inv because candle could decrease + return InteractionResult.TRY_WITH_EMPTY_HAND; + } + // Paper end - call change block event - stack.consume(1, player); + itemStack.consume(1, player); level.playSound(null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F); level.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleBlock)); -@@ -87,9 +_,28 @@ +@@ -95,9 +_,28 @@ if (!player.canEat(false)) { return InteractionResult.PASS; } else { + // Paper start - call change block event -+ int bitesValue = state.getValue(CakeBlock.BITES); -+ final BlockState newState = bitesValue < MAX_BITES ? state.setValue(CakeBlock.BITES, bitesValue + 1) : level.getFluidState(pos).createLegacyBlock(); ++ int bites = state.getValue(CakeBlock.BITES); ++ final BlockState newState = bites < MAX_BITES ? state.setValue(CakeBlock.BITES, bites + 1) : level.getFluidState(pos).createLegacyBlock(); + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { + ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); + return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles @@ -27,9 +27,10 @@ + // Paper end - call change block event player.awardStat(Stats.EAT_CAKE_SLICE); - player.getFoodData().eat(2, 0.1F); -- int bitesValue = state.getValue(BITES); +- int bites = state.getValue(BITES); + // CraftBukkit start + // player.getFoodData().eat(2, 0.1F); ++ // int bites = state.getValue(BITES); // Paper - move up + int oldFoodLevel = player.getFoodData().foodLevel; + + org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel); @@ -40,7 +41,6 @@ + + ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); + // CraftBukkit end -+ // Paper - move up level.gameEvent(player, GameEvent.EAT, pos); - if (bitesValue < 6) { - level.setBlock(pos, state.setValue(BITES, bitesValue + 1), Block.UPDATE_ALL); + if (bites < 6) { + level.setBlock(pos, state.setValue(BITES, bites + 1), Block.UPDATE_ALL); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch index ba3a3eb68533..c21b9f52a73c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch @@ -1,25 +1,25 @@ --- a/net/minecraft/world/level/block/CampfireBlock.java +++ b/net/minecraft/world/level/block/CampfireBlock.java -@@ -107,8 +_,9 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -120,8 +_,9 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (state.getValue(LIT) && entity instanceof LivingEntity) { - entity.hurt(level.damageSources().campfire(), this.fireDamage); + entity.hurt(level.damageSources().campfire().eventBlockDamager(level, pos), this.fireDamage); // CraftBukkit } - super.entityInside(state, level, pos, entity, effectApplier, pastEdges); -@@ -219,6 +_,11 @@ - && projectile.mayInteract(serverLevel, blockPos) + super.entityInside(state, level, pos, entity, effectApplier, isPrecise); +@@ -232,6 +_,11 @@ + && projectile.mayInteract(serverLevel, pos) && !state.getValue(LIT) && !state.getValue(WATERLOGGED)) { + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, blockPos, projectile).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, pos, projectile).isCancelled()) { + return; + } + // CraftBukkit end - level.setBlock(blockPos, state.setValue(BlockStateProperties.LIT, true), Block.UPDATE_ALL_IMMEDIATE); + level.setBlock(pos, state.setValue(BlockStateProperties.LIT, true), Block.UPDATE_ALL_IMMEDIATE); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CartographyTableBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CartographyTableBlock.java.patch index abb169e797f7..6fed31ca1cce 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CartographyTableBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CartographyTableBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/CartographyTableBlock.java +++ b/net/minecraft/world/level/block/CartographyTableBlock.java -@@ -32,8 +_,9 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -34,8 +_,9 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch index 1536368b6288..53f2111574c8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch @@ -3,18 +3,18 @@ @@ -87,6 +_,7 @@ CopperGolem copperGolem = EntityType.COPPER_GOLEM.create(level, EntitySpawnReason.TRIGGERED); if (copperGolem != null) { - spawnGolemInWorld(level, blockPatternMatch2, copperGolem, blockPatternMatch2.getBlock(0, 0, 0).getPos()); + spawnGolemInWorld(level, copperGolemMatch, copperGolem, copperGolemMatch.getBlock(0, 0, 0).getPos()); + if (!copperGolem.valid) return; // Paper - entityspawnevent - entity was not added to the world so prevent world mutation - this.replaceCopperBlockWithChest(level, blockPatternMatch2); - copperGolem.spawn(this.getWeatherStateFromPattern(blockPatternMatch2)); + this.replaceCopperBlockWithChest(level, copperGolemMatch); + copperGolem.spawn(this.getWeatherStateFromPattern(copperGolemMatch)); } @@ -105,9 +_,22 @@ } - private static void spawnGolemInWorld(Level level, BlockPattern.BlockPatternMatch patternMatch, Entity golem, BlockPos pos) { -- clearPatternBlocks(level, patternMatch); + private static void spawnGolemInWorld(final Level level, final BlockPattern.BlockPatternMatch match, final Entity golem, final BlockPos spawnPos) { +- clearPatternBlocks(level, match); + // clearPatternBlocks(level, patternMatch); // Paper - moved down - golem.snapTo(pos.getX() + 0.5, pos.getY() + 0.05, pos.getZ() + 0.5, 0.0F, 0.0F); + golem.snapTo(spawnPos.getX() + 0.5, spawnPos.getY() + 0.05, spawnPos.getZ() + 0.5, 0.0F, 0.0F); - level.addFreshEntity(golem); + // Paper start + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; @@ -29,7 +29,7 @@ + return; + } + // Paper end -+ clearPatternBlocks(level, patternMatch); // Paper - from above ++ clearPatternBlocks(level, match); // Paper - from above - for (ServerPlayer serverPlayer : level.getEntitiesOfClass(ServerPlayer.class, golem.getBoundingBox().inflate(5.0))) { - CriteriaTriggers.SUMMONED_ENTITY.trigger(serverPlayer, golem); + for (ServerPlayer player : level.getEntitiesOfClass(ServerPlayer.class, golem.getBoundingBox().inflate(5.0))) { + CriteriaTriggers.SUMMONED_ENTITY.trigger(player, golem); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch index dd650a6c3c59..d2ec874aad2d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/CauldronBlock.java +++ b/net/minecraft/world/level/block/CauldronBlock.java @@ -40,9 +_,19 @@ - public void handlePrecipitation(BlockState state, Level level, BlockPos pos, Biome.Precipitation precipitation) { + public void handlePrecipitation(final BlockState state, final Level level, final BlockPos pos, final Biome.Precipitation precipitation) { if (shouldHandlePrecipitation(level, precipitation)) { if (precipitation == Biome.Precipitation.RAIN) { + // Paper start - Call CauldronLevelChangeEvent @@ -21,23 +21,23 @@ level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos); } @@ -58,13 +_,19 @@ - protected void receiveStalactiteDrip(BlockState state, Level level, BlockPos pos, Fluid fluid) { + protected void receiveStalactiteDrip(final BlockState state, final Level level, final BlockPos pos, final Fluid fluid) { if (fluid == Fluids.WATER) { - BlockState blockState = Blocks.WATER_CAULDRON.defaultBlockState(); -- level.setBlockAndUpdate(pos, blockState); -- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + BlockState newState = Blocks.WATER_CAULDRON.defaultBlockState(); +- level.setBlockAndUpdate(pos, newState); +- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); + // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled -+ if (!LayeredCauldronBlock.changeLevel(level, pos, blockState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit ++ if (!LayeredCauldronBlock.changeLevel(level, pos, newState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit + return; + } + // Paper end - Call CauldronLevelChangeEvent level.levelEvent(LevelEvent.SOUND_DRIP_WATER_INTO_CAULDRON, pos, 0); } else if (fluid == Fluids.LAVA) { - BlockState blockState = Blocks.LAVA_CAULDRON.defaultBlockState(); -- level.setBlockAndUpdate(pos, blockState); -- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + BlockState newState = Blocks.LAVA_CAULDRON.defaultBlockState(); +- level.setBlockAndUpdate(pos, newState); +- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); + // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled -+ if (!LayeredCauldronBlock.changeLevel(level, pos, blockState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit ++ if (!LayeredCauldronBlock.changeLevel(level, pos, newState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit + return; + } + // Paper end - Call CauldronLevelChangeEvent diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CaveVines.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CaveVines.java.patch index deaefa83917c..a6825d1f7b45 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CaveVines.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CaveVines.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/CaveVines.java +++ b/net/minecraft/world/level/block/CaveVines.java @@ -23,6 +_,12 @@ - static InteractionResult use(Entity entity, BlockState state, Level level, BlockPos pos) { + static InteractionResult use(final Entity sourceEntity, final BlockState state, final Level level, final BlockPos pos) { if (state.getValue(BERRIES)) { if (level instanceof ServerLevel serverLevel) { + // CraftBukkit start - call entity change block event -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.setValue(CaveVines.BERRIES, false))) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, state.setValue(CaveVines.BERRIES, false))) { + return InteractionResult.SUCCESS; + } + // CraftBukkit end - call entity change block event @@ -16,12 +16,12 @@ @@ -30,8 +_,25 @@ level.getBlockEntity(pos), null, - entity, -- (serverLevel1, itemStack) -> Block.popResource(serverLevel1, pos, itemStack) -+ (serverLevel1, itemStack) -> drops.add(itemStack) // Paper - call player harvest block event - store drops from loottable + sourceEntity, +- (serverlvl, itemStack) -> Block.popResource(serverlvl, pos, itemStack) ++ (serverlvl, itemStack) -> drops.add(itemStack) // Paper - call player harvest block event - store drops from loottable ); + // Paper start - call player harvest block event -+ if (entity instanceof net.minecraft.world.entity.player.Player player) { ++ if (sourceEntity instanceof net.minecraft.world.entity.player.Player player) { + org.bukkit.event.player.PlayerHarvestBlockEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerHarvestBlockEvent( + level, pos, player, net.minecraft.world.InteractionHand.MAIN_HAND, drops + ); @@ -37,6 +37,6 @@ + } + } + // Paper end - call player harvest block event - float f = Mth.randomBetween(serverLevel.random, 0.8F, 1.2F); - serverLevel.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, f); - BlockState blockState = state.setValue(BERRIES, false); + float pitch = Mth.randomBetween(serverLevel.getRandom(), 0.8F, 1.2F); + serverLevel.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, pitch); + BlockState newState = state.setValue(BERRIES, false); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch index 332ca736380d..ca13ce4d6f2e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch @@ -1,20 +1,21 @@ --- a/net/minecraft/world/level/block/CaveVinesBlock.java +++ b/net/minecraft/world/level/block/CaveVinesBlock.java -@@ -52,8 +_,15 @@ +@@ -52,8 +_,16 @@ @Override - protected BlockState getGrowIntoState(BlockState state, RandomSource random) { -- return super.getGrowIntoState(state, random).setValue(BERRIES, random.nextFloat() < 0.11F); + protected BlockState getGrowIntoState(final BlockState growFromState, final RandomSource random) { +- return super.getGrowIntoState(growFromState, random).setValue(BERRIES, random.nextFloat() < 0.11F); - } -+ // Paper start - Fix Spigot growth modifiers -+ return this.getGrowIntoState(state, random, null); ++ // Paper start - Fix Spigot growth modifiers ++ return this.getGrowIntoState(growFromState, random, null); + } ++ + @Override -+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { ++ protected BlockState getGrowIntoState(BlockState growFromState, RandomSource random, @org.jspecify.annotations.Nullable Level level) { + final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F); -+ return super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value); ++ return super.getGrowIntoState(growFromState, random).setValue(CaveVinesBlock.BERRIES, value); + } + // Paper end - Fix Spigot growth modifiers @Override - protected ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state, boolean includeData) { + protected ItemStack getCloneItemStack(final LevelReader level, final BlockPos pos, final BlockState state, final boolean includeData) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CeilingHangingSignBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CeilingHangingSignBlock.java.patch index 5acb1aad3f25..7b55fc8b18f8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CeilingHangingSignBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CeilingHangingSignBlock.java.patch @@ -1,10 +1,11 @@ --- a/net/minecraft/world/level/block/CeilingHangingSignBlock.java +++ b/net/minecraft/world/level/block/CeilingHangingSignBlock.java -@@ -165,6 +_,6 @@ +@@ -177,7 +_,7 @@ @Override - public @Nullable BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { -- return createTickerHelper(blockEntityType, BlockEntityType.HANGING_SIGN, SignBlockEntity::tick); + public @Nullable BlockEntityTicker getTicker(final Level level, final BlockState blockState, final BlockEntityType type) { +- return createTickerHelper(type, BlockEntityType.HANGING_SIGN, SignBlockEntity::tick); + return null; // CraftBukkit - remove unnecessary sign ticking } - } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch index 8c1b3977c7be..cf23f85f585e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/ChangeOverTimeBlock.java +++ b/net/minecraft/world/level/block/ChangeOverTimeBlock.java @@ -16,7 +_,7 @@ - default void changeOverTime(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - float f = 0.05688889F; + default void changeOverTime(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + float eachBlockOncePerDayChance = 0.05688889F; if (random.nextFloat() < 0.05688889F) { -- this.getNextState(state, level, pos, random).ifPresent(blockState -> level.setBlockAndUpdate(pos, blockState)); -+ this.getNextState(state, level, pos, random).ifPresent(blockState -> org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, blockState, Block.UPDATE_ALL)); // CraftBukkit +- this.getNextState(state, level, pos, random).ifPresent(weatheredState -> level.setBlockAndUpdate(pos, weatheredState)); ++ this.getNextState(state, level, pos, random).ifPresent(weatheredState -> org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, weatheredState, Block.UPDATE_ALL)); // CraftBukkit } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch index af84505e929e..d5302a1a3a0d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/level/block/ChestBlock.java +++ b/net/minecraft/world/level/block/ChestBlock.java -@@ -96,7 +_,7 @@ +@@ -97,7 +_,7 @@ @Override public Optional acceptDouble(final ChestBlockEntity first, final ChestBlockEntity second) { final Container container = new CompoundContainer(first, second); - return Optional.of(new MenuProvider() { + return Optional.of(DoubleInventory.wrap(new MenuProvider() { // CraftBukkit - wrap for identification - @Override - public @Nullable AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { - if (first.canOpen(player) && second.canOpen(player)) { -@@ -117,10 +_,10 @@ + { + Objects.requireNonNull(container); + } +@@ -122,10 +_,10 @@ if (first.hasCustomName()) { return first.getDisplayName(); } else { @@ -22,7 +22,7 @@ } @Override -@@ -134,6 +_,34 @@ +@@ -139,6 +_,34 @@ } }; @@ -57,8 +57,8 @@ @Override public MapCodec codec() { return CODEC; -@@ -261,8 +_,7 @@ - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -268,8 +_,7 @@ + ) { if (level instanceof ServerLevel serverLevel) { MenuProvider menuProvider = this.getMenuProvider(state, level, pos); - if (menuProvider != null) { @@ -67,31 +67,30 @@ player.awardStat(this.getOpenChestStat()); PiglinAi.angerNearbyPiglins(serverLevel, player, true); } -@@ -299,7 +_,14 @@ +@@ -310,7 +_,13 @@ @Override - public @Nullable MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) { + public @Nullable MenuProvider getMenuProvider(final BlockState state, final Level level, final BlockPos pos) { - return this.combine(state, level, pos, false).apply(MENU_PROVIDER_COMBINER).orElse(null); + // CraftBukkit start + return this.getMenuProvider(state, level, pos, false); + } + -+ @Nullable -+ public MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos, boolean ignoreObstructions) { ++ public @Nullable MenuProvider getMenuProvider(final BlockState state, final Level level, final BlockPos pos, final boolean ignoreObstructions) { + return this.combine(state, level, pos, ignoreObstructions).apply(MENU_PROVIDER_COMBINER).orElse(null); + // CraftBukkit end } - public static DoubleBlockCombiner.Combiner opennessCombiner(final LidBlockEntity lid) { -@@ -341,6 +_,11 @@ + public static DoubleBlockCombiner.Combiner opennessCombiner(final LidBlockEntity entity) { +@@ -352,6 +_,11 @@ } - private static boolean isCatSittingOnChest(LevelAccessor level, BlockPos pos) { + private static boolean isCatSittingOnChest(final LevelAccessor level, final BlockPos pos) { + // Paper start - Option to disable chest cat detection + if (level.getMinecraftWorld().paperConfig().entities.behavior.disableChestCatDetection) { + return false; + } + // Paper end - Option to disable chest cat detection - List entitiesOfClass = level.getEntitiesOfClass( - Cat.class, new AABB(pos.getX(), pos.getY() + 1, pos.getZ(), pos.getX() + 1, pos.getY() + 2, pos.getZ() + 1) - ); + List cats = level.getEntitiesOfClass(Cat.class, new AABB(pos.getX(), pos.getY() + 1, pos.getZ(), pos.getX() + 1, pos.getY() + 2, pos.getZ() + 1)); + if (!cats.isEmpty()) { + for (Cat cat : cats) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChorusFlowerBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChorusFlowerBlock.java.patch index 18bfe77bae2f..97b4fd409217 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChorusFlowerBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChorusFlowerBlock.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/level/block/ChorusFlowerBlock.java +++ b/net/minecraft/world/level/block/ChorusFlowerBlock.java -@@ -96,8 +_,10 @@ +@@ -94,8 +_,9 @@ } - if (flag && allNeighborsEmpty(level, blockPos, null) && level.isEmptyBlock(pos.above(2))) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, this.defaultBlockState().setValue(AGE, ageValue), Block.UPDATE_CLIENTS)) { // CraftBukkit - add event - level.setBlock(pos, ChorusPlantBlock.getStateWithConnections(level, pos, this.plant.defaultBlockState()), Block.UPDATE_CLIENTS); - this.placeGrownFlower(level, blockPos, ageValue); + if (growUpwards && allNeighborsEmpty(level, above, null) && level.isEmptyBlock(pos.above(2))) { +- level.setBlock(pos, ChorusPlantBlock.getStateWithConnections(level, pos, this.plant.defaultBlockState()), Block.UPDATE_CLIENTS); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, above, this.defaultBlockState().setValue(AGE, currentAge), Block.UPDATE_CLIENTS)) { // CraftBukkit - add event + this.placeGrownFlower(level, above, currentAge); + } // CraftBukkit - } else if (ageValue < 4) { - int i = random.nextInt(4); - if (flag1) { -@@ -112,30 +_,40 @@ - if (level.isEmptyBlock(blockPos1) - && level.isEmptyBlock(blockPos1.below()) - && allNeighborsEmpty(level, blockPos1, randomDirection.getOpposite())) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos1, this.defaultBlockState().setValue(AGE, ageValue + 1), Block.UPDATE_CLIENTS)) { // CraftBukkit - add event - this.placeGrownFlower(level, blockPos1, ageValue + 1); - flag2 = true; + } else if (currentAge < 4) { + int numBranchAttempts = random.nextInt(4); + if (pillarOnSupportBlock) { +@@ -108,30 +_,40 @@ + Direction direction = Direction.Plane.HORIZONTAL.getRandomDirection(random); + BlockPos target = pos.relative(direction); + if (level.isEmptyBlock(target) && level.isEmptyBlock(target.below()) && allNeighborsEmpty(level, target, direction.getOpposite())) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, target, this.defaultBlockState().setValue(AGE, currentAge + 1), Block.UPDATE_CLIENTS)) { // CraftBukkit - add event + this.placeGrownFlower(level, target, currentAge + 1); + createdBranch = true; + } // CraftBukkit } } - if (flag2) { + if (createdBranch) { level.setBlock(pos, ChorusPlantBlock.getStateWithConnections(level, pos, this.plant.defaultBlockState()), Block.UPDATE_CLIENTS); } else { + // CraftBukkit start - add event @@ -42,27 +42,27 @@ } } - private void placeGrownFlower(Level level, BlockPos pos, int age) { + private void placeGrownFlower(final Level level, final BlockPos pos, final int age) { - level.setBlock(pos, this.defaultBlockState().setValue(AGE, age), Block.UPDATE_CLIENTS); + // level.setBlock(pos, this.defaultBlockState().setValue(AGE, age), Block.UPDATE_CLIENTS); // Paper - already done above in the event call level.levelEvent(LevelEvent.SOUND_CHORUS_GROW, pos, 0); } - private void placeDeadFlower(Level level, BlockPos pos) { + private void placeDeadFlower(final Level level, final BlockPos pos) { - level.setBlock(pos, this.defaultBlockState().setValue(AGE, 5), Block.UPDATE_CLIENTS); + // level.setBlock(pos, this.defaultBlockState().setValue(AGE, 5), Block.UPDATE_CLIENTS); // Paper - already done above in the event call level.levelEvent(LevelEvent.SOUND_CHORUS_DEATH, pos, 0); } -@@ -261,6 +_,11 @@ - protected void onProjectileHit(Level level, BlockState state, BlockHitResult hit, Projectile projectile) { - BlockPos blockPos = hit.getBlockPos(); - if (level instanceof ServerLevel serverLevel && projectile.mayInteract(serverLevel, blockPos) && projectile.mayBreak(serverLevel)) { +@@ -257,6 +_,11 @@ + protected void onProjectileHit(final Level level, final BlockState state, final BlockHitResult blockHit, final Projectile projectile) { + BlockPos pos = blockHit.getBlockPos(); + if (level instanceof ServerLevel serverLevel && projectile.mayInteract(serverLevel, pos) && projectile.mayBreak(serverLevel)) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockPos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + return; + } + // CraftBukkit end - level.destroyBlock(blockPos, true, projectile); + level.destroyBlock(pos, true, projectile); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChorusPlantBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChorusPlantBlock.java.patch index f73493ba87e9..79a13ee7978f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChorusPlantBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChorusPlantBlock.java.patch @@ -1,34 +1,34 @@ --- a/net/minecraft/world/level/block/ChorusPlantBlock.java +++ b/net/minecraft/world/level/block/ChorusPlantBlock.java -@@ -38,6 +_,7 @@ +@@ -39,6 +_,7 @@ @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { + public BlockState getStateForPlacement(final BlockPlaceContext context) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates return getStateWithConnections(context.getLevel(), context.getClickedPos(), this.defaultBlockState()); } -@@ -68,6 +_,7 @@ - BlockState neighborState, - RandomSource random +@@ -69,6 +_,7 @@ + final BlockState neighbourState, + final RandomSource random ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return state; // Paper - add option to disable block updates if (!state.canSurvive(level, pos)) { - scheduledTickAccess.scheduleTick(pos, this, 1); - return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); -@@ -81,6 +_,7 @@ + ticks.scheduleTick(pos, this, 1); + return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); +@@ -82,6 +_,7 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return; // Paper - add option to disable block updates if (!state.canSurvive(level, pos)) { level.destroyBlock(pos, true); } -@@ -88,6 +_,7 @@ +@@ -89,6 +_,7 @@ @Override - protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + protected boolean canSurvive(final BlockState state, final LevelReader level, final BlockPos pos) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return true; // Paper - add option to disable block updates - BlockState blockState = level.getBlockState(pos.below()); - boolean flag = !level.getBlockState(pos.above()).isAir() && !blockState.isAir(); + BlockState belowState = level.getBlockState(pos.below()); + boolean blockAboveOrBelow = !level.getBlockState(pos.above()).isAir() && !belowState.isAir(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CocoaBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CocoaBlock.java.patch index 687be11e086e..96da0cba2dff 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CocoaBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CocoaBlock.java.patch @@ -3,20 +3,20 @@ @@ -50,10 +_,10 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { -- if (level.random.nextInt(5) == 0) { -+ if (level.random.nextFloat() < (level.spigotConfig.cocoaModifier / (100.0F * 5))) { // Spigot - SPIGOT-7159: Better modifier resolution - int ageValue = state.getValue(AGE); - if (ageValue < 2) { -- level.setBlock(pos, state.setValue(AGE, ageValue + 1), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(AGE, ageValue + 1), Block.UPDATE_CLIENTS); // CraftBukkit + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { +- if (level.getRandom().nextInt(5) == 0) { ++ if (level.getRandom().nextFloat() < (level.spigotConfig.cocoaModifier / (100.0F * 5))) { // Spigot - SPIGOT-7159: Better modifier resolution + int age = state.getValue(AGE); + if (age < 2) { +- level.setBlock(pos, state.setValue(AGE, age + 1), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(AGE, age + 1), Block.UPDATE_CLIENTS); // CraftBukkit } } } @@ -115,7 +_,7 @@ @Override - public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + public void performBonemeal(final ServerLevel level, final RandomSource random, final BlockPos pos, final BlockState state) { - level.setBlock(pos, state.setValue(AGE, state.getValue(AGE) + 1), Block.UPDATE_CLIENTS); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(AGE, state.getValue(AGE) + 1), Block.UPDATE_CLIENTS); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CommandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CommandBlock.java.patch index ee56dfd5efd5..191ac3f8f05b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CommandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CommandBlock.java.patch @@ -1,24 +1,27 @@ --- a/net/minecraft/world/level/block/CommandBlock.java +++ b/net/minecraft/world/level/block/CommandBlock.java -@@ -70,6 +_,15 @@ +@@ -69,8 +_,17 @@ + } + } - private void setPoweredAndUpdate(Level level, BlockPos pos, CommandBlockEntity blockEntity, boolean powered) { - boolean isPowered = blockEntity.isPowered(); +- private void setPoweredAndUpdate(final Level level, final BlockPos pos, final CommandBlockEntity commandBlock, final boolean isPowered) { ++ private void setPoweredAndUpdate(final Level level, final BlockPos pos, final CommandBlockEntity commandBlock, boolean isPowered) { // Paper - remove final from isPowered + boolean wasPowered = commandBlock.isPowered(); + // CraftBukkit start + org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ int old = isPowered ? 15 : 0; -+ int current = powered ? 15 : 0; ++ int old = wasPowered ? 15 : 0; ++ int current = isPowered ? 15 : 0; + + org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, old, current); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); -+ powered = eventRedstone.getNewCurrent() > 0; ++ isPowered = eventRedstone.getNewCurrent() > 0; + // CraftBukkit end - if (powered != isPowered) { - blockEntity.setPowered(powered); - if (powered) { -@@ -126,7 +_,7 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (isPowered != wasPowered) { + commandBlock.setPowered(isPowered); + if (isPowered) { +@@ -129,7 +_,7 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) { + if (blockEntity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch index c238837a1b3d..751e64caf7ef 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/block/ComparatorBlock.java +++ b/net/minecraft/world/level/block/ComparatorBlock.java @@ -167,8 +_,18 @@ - boolean shouldTurnOn = this.shouldTurnOn(level, pos, state); - boolean poweredValue = state.getValue(POWERED); - if (poweredValue && !shouldTurnOn) { + boolean sourceOn = this.shouldTurnOn(level, pos, state); + boolean isOn = state.getValue(POWERED); + if (isOn && !sourceOn) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) { + return; + } + // CraftBukkit end level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_CLIENTS); - } else if (!poweredValue && shouldTurnOn) { + } else if (!isOn && sourceOn) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) { + return; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch index da102b9c2e84..37f69c8d76c9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch @@ -1,74 +1,79 @@ --- a/net/minecraft/world/level/block/ComposterBlock.java +++ b/net/minecraft/world/level/block/ComposterBlock.java -@@ -252,6 +_,11 @@ - if (levelValue < 8 && COMPOSTABLES.containsKey(stack.getItem())) { - if (levelValue < 7 && !level.isClientSide()) { - BlockState blockState = addItem(player, state, level, pos, stack); +@@ -258,6 +_,11 @@ + if (fillLevel < 8 && COMPOSTABLES.containsKey(itemStack.getItem())) { + if (fillLevel < 7 && !level.isClientSide()) { + BlockState newState = addItem(player, state, level, pos, itemStack); + // Paper start - handle cancelled events -+ if (blockState == null) { ++ if (newState == null) { + return InteractionResult.PASS; + } + // Paper end - level.levelEvent(LevelEvent.COMPOSTER_FILL, pos, state != blockState ? 1 : 0); - player.awardStat(Stats.ITEM_USED.get(stack.getItem())); - stack.consume(1, player); -@@ -277,7 +_,19 @@ - public static BlockState insertItem(Entity entity, BlockState state, ServerLevel level, ItemStack stack, BlockPos pos) { - int levelValue = state.getValue(LEVEL); - if (levelValue < 7 && COMPOSTABLES.containsKey(stack.getItem())) { -- BlockState blockState = addItem(entity, state, level, pos, stack); + level.levelEvent(LevelEvent.COMPOSTER_FILL, pos, state != newState ? 1 : 0); + player.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); + itemStack.consume(1, player); +@@ -287,7 +_,19 @@ + ) { + int fillLevel = state.getValue(LEVEL); + if (fillLevel < 7 && COMPOSTABLES.containsKey(itemStack.getItem())) { +- BlockState newState = addItem(sourceEntity, state, level, pos, itemStack); + // CraftBukkit start + double rand = level.getRandom().nextDouble(); -+ BlockState blockState = null; // Paper -+ if (false && (state == blockState || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, blockState))) { // Paper - move event call into addItem ++ BlockState newState = null; // Paper ++ if (false && (state == newState || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, newState))) { // Paper - move event call into addItem + return state; + } -+ blockState = ComposterBlock.addItem(entity, state, level, pos, stack, rand); ++ newState = ComposterBlock.addItem(sourceEntity, state, level, pos, itemStack, rand); + // Paper start - handle cancelled events -+ if (blockState == null) { ++ if (newState == null) { + return state; + } + // Paper end + // CraftBukkit end - stack.shrink(1); - return blockState; + itemStack.shrink(1); + return newState; } else { -@@ -286,6 +_,14 @@ +@@ -296,6 +_,14 @@ } - public static BlockState extractProduce(Entity entity, BlockState state, Level level, BlockPos pos) { + public static BlockState extractProduce(final Entity sourceEntity, final BlockState state, final Level level, final BlockPos pos) { + // CraftBukkit start -+ if (entity != null && !(entity instanceof Player)) { -+ BlockState emptyState = ComposterBlock.empty(entity, state, org.bukkit.craftbukkit.util.DummyGeneratorAccess.INSTANCE, pos); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, emptyState)) { ++ if (!(sourceEntity instanceof Player)) { ++ BlockState emptyState = ComposterBlock.empty(sourceEntity, state, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, pos); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, emptyState)) { + return state; + } + } + // CraftBukkit end if (!level.isClientSide()) { - Vec3 vec3 = Vec3.atLowerCornerWithOffset(pos, 0.5, 1.01, 0.5).offsetRandomXZ(level.random, 0.7F); - ItemEntity itemEntity = new ItemEntity(level, vec3.x(), vec3.y(), vec3.z(), new ItemStack(Items.BONE_MEAL)); -@@ -305,14 +_,39 @@ - return blockState; + Vec3 itemPos = Vec3.atLowerCornerWithOffset(pos, 0.5, 1.01, 0.5).offsetRandomXZ(level.getRandom(), 0.7F); + ItemEntity entity = new ItemEntity(level, itemPos.x(), itemPos.y(), itemPos.z(), new ItemStack(Items.BONE_MEAL)); +@@ -315,16 +_,44 @@ + return newState; } + @Nullable // Paper - static BlockState addItem(@Nullable Entity entity, BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack) { + private static BlockState addItem( + final @Nullable Entity sourceEntity, final BlockState state, final LevelAccessor level, final BlockPos pos, final ItemStack itemStack + ) { + // CraftBukkit start -+ return ComposterBlock.addItem(entity, state, level, pos, stack, level.getRandom().nextDouble()); ++ return ComposterBlock.addItem(sourceEntity, state, level, pos, itemStack, level.getRandom().nextDouble()); + } + @Nullable // Paper - make it nullable -+ static BlockState addItem(@Nullable Entity entity, BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack, double rand) { - int levelValue = state.getValue(LEVEL); - float _float = COMPOSTABLES.getFloat(stack.getItem()); -- if ((levelValue != 0 || !(_float > 0.0F)) && !(level.getRandom().nextDouble() < _float)) { ++ private static BlockState addItem( ++ final @Nullable Entity sourceEntity, final BlockState state, final LevelAccessor level, final BlockPos pos, final ItemStack itemStack, final double rand ++ // CraftBukkit end ++ ) { + int fillLevel = state.getValue(LEVEL); + float chance = COMPOSTABLES.getFloat(itemStack.getItem()); +- if ((fillLevel != 0 || !(chance > 0.0F)) && !(level.getRandom().nextDouble() < chance)) { + // Paper start - Add CompostItemEvent and EntityCompostItemEvent -+ boolean willRaiseLevel = !((levelValue != 0 || _float <= 0.0F) && rand >= (double) _float); ++ boolean willRaiseLevel = !((fillLevel != 0 || chance <= 0.0F) && rand >= (double) chance); + final io.papermc.paper.event.block.CompostItemEvent event; -+ if (entity == null) { -+ event = new io.papermc.paper.event.block.CompostItemEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), stack.getBukkitStack(), willRaiseLevel); ++ if (sourceEntity == null) { ++ event = new io.papermc.paper.event.block.CompostItemEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), itemStack.getBukkitStack(), willRaiseLevel); + } else { -+ event = new io.papermc.paper.event.entity.EntityCompostItemEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), stack.getBukkitStack(), willRaiseLevel); ++ event = new io.papermc.paper.event.entity.EntityCompostItemEvent(sourceEntity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), itemStack.getBukkitStack(), willRaiseLevel); + } + if (!event.callEvent()) { // check for cancellation of entity event (non entity event can't be cancelled cause of hoppers) + return null; @@ -79,22 +84,22 @@ + // Paper end - Add CompostItemEvent and EntityCompostItemEvent return state; } else { - int i = levelValue + 1; - BlockState blockState = state.setValue(LEVEL, i); + int newLevel = fillLevel + 1; + BlockState newState = state.setValue(LEVEL, newLevel); + // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events -+ if (entity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, blockState)) { ++ if (sourceEntity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, newState)) { + return null; + } + // Paper end - level.setBlock(pos, blockState, Block.UPDATE_ALL); - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, blockState)); - if (i == 7) { -@@ -357,13 +_,14 @@ - if (levelValue == 8) { + level.setBlock(pos, newState, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); + if (newLevel == 7) { +@@ -369,13 +_,14 @@ + if (contentLevel == 8) { return new ComposterBlock.OutputContainer(state, level, pos, new ItemStack(Items.BONE_MEAL)); } else { -- return (WorldlyContainer)(levelValue < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer()); -+ return (WorldlyContainer)(levelValue < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer(level, pos)); // CraftBukkit - empty generatoraccess, blockposition +- return (WorldlyContainer)(contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer()); ++ return (WorldlyContainer)(contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer(level, pos)); // CraftBukkit - empty levelAccessor, blockPos } } @@ -106,35 +111,35 @@ } @Override -@@ -390,6 +_,7 @@ +@@ -402,6 +_,7 @@ - public InputContainer(BlockState state, LevelAccessor level, BlockPos pos) { + public InputContainer(final BlockState state, final LevelAccessor level, final BlockPos pos) { super(1); + this.bukkitOwner = new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(level, pos, this); // CraftBukkit this.state = state; this.level = level; this.pos = pos; -@@ -421,6 +_,11 @@ - if (!item.isEmpty()) { +@@ -433,6 +_,11 @@ + if (!contents.isEmpty()) { this.changed = true; - BlockState blockState = ComposterBlock.addItem(null, this.state, this.level, this.pos, item); + BlockState newState = ComposterBlock.addItem(null, this.state, this.level, this.pos, contents); + // Paper start - Add CompostItemEvent and EntityCompostItemEvent -+ if (blockState == null) { ++ if (newState == null) { + return; + } + // Paper end - Add CompostItemEvent and EntityCompostItemEvent - this.level.levelEvent(LevelEvent.COMPOSTER_FILL, this.pos, blockState != this.state ? 1 : 0); + this.level.levelEvent(LevelEvent.COMPOSTER_FILL, this.pos, newState != this.state ? 1 : 0); this.removeItemNoUpdate(0); } -@@ -435,6 +_,7 @@ +@@ -447,6 +_,7 @@ - public OutputContainer(BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack) { - super(stack); + public OutputContainer(final BlockState state, final LevelAccessor level, final BlockPos pos, final ItemStack contents) { + super(contents); + this.bukkitOwner = new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(level, pos, this); // Paper this.state = state; this.level = level; this.pos = pos; -@@ -462,8 +_,15 @@ +@@ -474,8 +_,15 @@ @Override public void setChanged() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ConcretePowderBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ConcretePowderBlock.java.patch index 26a5973132e3..29c4e99ae8d9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ConcretePowderBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ConcretePowderBlock.java.patch @@ -1,67 +1,67 @@ --- a/net/minecraft/world/level/block/ConcretePowderBlock.java +++ b/net/minecraft/world/level/block/ConcretePowderBlock.java -@@ -38,16 +_,33 @@ +@@ -36,16 +_,33 @@ @Override - public void onLand(Level level, BlockPos pos, BlockState state, BlockState replaceableState, FallingBlockEntity fallingBlock) { - if (shouldSolidify(level, pos, replaceableState)) { + public void onLand(final Level level, final BlockPos pos, final BlockState state, final BlockState replacedBlock, final FallingBlockEntity entity) { + if (shouldSolidify(level, pos, replacedBlock)) { - level.setBlock(pos, this.concrete.defaultBlockState(), Block.UPDATE_ALL); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, this.concrete.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit } } @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { + public BlockState getStateForPlacement(final BlockPlaceContext context) { - BlockGetter level = context.getLevel(); + Level level = context.getLevel(); // Paper - BlockPos clickedPos = context.getClickedPos(); - BlockState blockState = level.getBlockState(clickedPos); -- return shouldSolidify(level, clickedPos, blockState) ? this.concrete.defaultBlockState() : super.getStateForPlacement(context); + BlockPos pos = context.getClickedPos(); + BlockState replacedBlock = level.getBlockState(pos); +- return shouldSolidify(level, pos, replacedBlock) ? this.concrete.defaultBlockState() : super.getStateForPlacement(context); + // CraftBukkit start -+ if (!ConcretePowderBlock.shouldSolidify(level, clickedPos, blockState)) { ++ if (!ConcretePowderBlock.shouldSolidify(level, pos, replacedBlock)) { + return super.getStateForPlacement(context); + } + + // TODO: An event factory call for methods like this -+ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState((net.minecraft.world.level.LevelAccessor) level, clickedPos); -+ craftBlockState.setData(this.concrete.defaultBlockState()); ++ org.bukkit.craftbukkit.block.CraftBlockState snapshot = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos); ++ snapshot.setBlock(this.concrete.defaultBlockState()); + -+ org.bukkit.event.block.BlockFormEvent event = new org.bukkit.event.block.BlockFormEvent(craftBlockState.getBlock(), craftBlockState); -+ level.getServer().server.getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockFormEvent event = new org.bukkit.event.block.BlockFormEvent(snapshot.getBlock(), snapshot); ++ event.callEvent(); + + if (!event.isCancelled()) { -+ return craftBlockState.getHandle(); ++ return snapshot.getHandle(); + } + + return super.getStateForPlacement(context); + // CraftBukkit end } - private static boolean shouldSolidify(BlockGetter level, BlockPos pos, BlockState state) { -@@ -88,9 +_,25 @@ - BlockState neighborState, - RandomSource random + private static boolean shouldSolidify(final BlockGetter level, final BlockPos pos, final BlockState replacedBlock) { +@@ -86,9 +_,25 @@ + final BlockState neighbourState, + final RandomSource random ) { - return touchesLiquid(level, pos) - ? this.concrete.defaultBlockState() -- : super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); +- : super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + // CraftBukkit start + if (ConcretePowderBlock.touchesLiquid(level, pos)) { + // Suppress during worldgen + if (!(level instanceof Level world1)) { + return this.concrete.defaultBlockState(); + } -+ org.bukkit.craftbukkit.block.CraftBlockState blockState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(world1, pos); -+ blockState.setData(this.concrete.defaultBlockState()); ++ org.bukkit.craftbukkit.block.CraftBlockState snapshot = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(world1, pos); ++ snapshot.setBlock(this.concrete.defaultBlockState()); + -+ org.bukkit.event.block.BlockFormEvent event = new org.bukkit.event.block.BlockFormEvent(blockState.getBlock(), blockState); ++ org.bukkit.event.block.BlockFormEvent event = new org.bukkit.event.block.BlockFormEvent(snapshot.getBlock(), snapshot); + world1.getCraftServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { -+ return blockState.getHandle(); ++ return snapshot.getHandle(); + } + } + -+ return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); ++ return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch index abf91f5579b1..f7127c58613a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/CopperGolemStatueBlock.java +++ b/net/minecraft/world/level/block/CopperGolemStatueBlock.java -@@ -107,15 +_,21 @@ - if (stack.is(ItemTags.AXES)) { +@@ -111,15 +_,21 @@ + if (itemStack.is(ItemTags.AXES)) { return InteractionResult.PASS; } else { - this.updatePose(level, state, pos, player); @@ -10,9 +10,9 @@ } } -- void updatePose(Level level, BlockState state, BlockPos pos, Player player) { +- void updatePose(final Level level, final BlockState state, final BlockPos pos, final Player player) { + // Paper start - call EntityChangeBlockEvent -+ InteractionResult updatePose(Level level, BlockState state, BlockPos pos, Player player) { ++ InteractionResult updatePose(final Level level, final BlockState state, final BlockPos pos, final Player player) { + BlockState newState = state.setValue(POSE, state.getValue(POSE).getNextPose()); + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { + return InteractionResult.PASS; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch index 685f6f642edc..f212c1876567 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/CoralBlock.java @@ -37,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!this.scanForWater(level, pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, this.deadBlock.defaultBlockState()).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CoralFanBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CoralFanBlock.java.patch index 107d539fbbf9..304c7fbcb959 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CoralFanBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CoralFanBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/CoralFanBlock.java +++ b/net/minecraft/world/level/block/CoralFanBlock.java -@@ -38,6 +_,11 @@ +@@ -37,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!scanForWater(state, level, pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, this.deadBlock.defaultBlockState().setValue(CoralFanBlock.WATERLOGGED, false)).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CoralPlantBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CoralPlantBlock.java.patch index d898a4c15b35..8b72b73aedbc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CoralPlantBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CoralPlantBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/CoralPlantBlock.java +++ b/net/minecraft/world/level/block/CoralPlantBlock.java -@@ -42,6 +_,11 @@ +@@ -41,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!scanForWater(state, level, pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, this.deadBlock.defaultBlockState().setValue(CoralPlantBlock.WATERLOGGED, false)).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CoralWallFanBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CoralWallFanBlock.java.patch index e21227fb17c6..9f4ccfad7d27 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CoralWallFanBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CoralWallFanBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/CoralWallFanBlock.java +++ b/net/minecraft/world/level/block/CoralWallFanBlock.java -@@ -38,6 +_,11 @@ +@@ -37,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!scanForWater(state, level, pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, this.deadBlock.defaultBlockState().setValue(CoralWallFanBlock.WATERLOGGED, false).setValue(CoralWallFanBlock.FACING, state.getValue(CoralWallFanBlock.FACING))).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CrafterBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CrafterBlock.java.patch index 853254707bcf..0384dbfd35f1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CrafterBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CrafterBlock.java.patch @@ -1,68 +1,68 @@ --- a/net/minecraft/world/level/block/CrafterBlock.java +++ b/net/minecraft/world/level/block/CrafterBlock.java -@@ -151,6 +_,13 @@ +@@ -155,6 +_,13 @@ } else { - RecipeHolder recipeHolder = potentialResults.get(); - ItemStack itemStack = recipeHolder.value().assemble(var11, level.registryAccess()); + RecipeHolder pickedRecipe = recipe.get(); + ItemStack results = pickedRecipe.value().assemble(var11); + // CraftBukkit start -+ org.bukkit.event.block.CrafterCraftEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callCrafterCraftEvent(pos, level, itemStack, recipeHolder); ++ org.bukkit.event.block.CrafterCraftEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callCrafterCraftEvent(pos, level, results, pickedRecipe); + if (event.isCancelled()) { + return; + } -+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResult()); ++ results = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResult()); + // CraftBukkit end - if (itemStack.isEmpty()) { + if (results.isEmpty()) { level.levelEvent(LevelEvent.SOUND_CRAFTER_FAIL, pos, 0); } else { -@@ -185,7 +_,25 @@ - Container containerAt = HopperBlockEntity.getContainerAt(level, pos.relative(direction)); - ItemStack itemStack = stack.copy(); - if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackSize(stack))) { +@@ -196,7 +_,25 @@ + Container into = HopperBlockEntity.getContainerAt(level, pos.relative(direction)); + ItemStack remaining = results.copy(); + if (into != null && (into instanceof CrafterBlockEntity || results.getCount() > into.getMaxStackSize(results))) { + // CraftBukkit start - InventoryMoveItemEvent -+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(remaining); + + org.bukkit.inventory.Inventory destinationInventory; + // Have to special case large chests as they work oddly -+ if (containerAt instanceof net.minecraft.world.CompoundContainer compoundContainer) { ++ if (into instanceof net.minecraft.world.CompoundContainer compoundContainer) { + destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); + } else { -+ destinationInventory = containerAt.getOwner().getInventory(); ++ destinationInventory = into.getOwner().getInventory(); + } + -+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(crafter.getOwner().getInventory(), oitemstack, destinationInventory, true); ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); + level.getCraftServer().getPluginManager().callEvent(event); -+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); - while (!itemStack.isEmpty()) { ++ remaining = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); + while (!remaining.isEmpty()) { + if (event.isCancelled()) { + break; + } + // CraftBukkit end - ItemStack itemStack1 = itemStack.copyWithCount(1); - ItemStack itemStack2 = HopperBlockEntity.addItem(crafter, containerAt, itemStack1, direction.getOpposite()); - if (!itemStack2.isEmpty()) { -@@ -195,7 +_,25 @@ - itemStack.shrink(1); + ItemStack copy = remaining.copyWithCount(1); + ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, into, copy, direction.getOpposite()); + if (!itemStack.isEmpty()) { +@@ -206,7 +_,25 @@ + remaining.shrink(1); } - } else if (containerAt != null) { + } else if (into != null) { + // CraftBukkit start - InventoryMoveItemEvent -+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(remaining); + + org.bukkit.inventory.Inventory destinationInventory; + // Have to special case large chests as they work oddly -+ if (containerAt instanceof net.minecraft.world.CompoundContainer compoundContainer) { ++ if (into instanceof net.minecraft.world.CompoundContainer compoundContainer) { + destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); + } else { -+ destinationInventory = containerAt.getOwner().getInventory(); ++ destinationInventory = into.getOwner().getInventory(); + } + -+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(crafter.getOwner().getInventory(), oitemstack, destinationInventory, true); ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); + level.getCraftServer().getPluginManager().callEvent(event); -+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); - while (!itemStack.isEmpty()) { ++ remaining = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); + while (!remaining.isEmpty()) { + if (event.isCancelled()) { + break; + } + // CraftBukkit end - int count = itemStack.getCount(); - itemStack = HopperBlockEntity.addItem(crafter, containerAt, itemStack, direction.getOpposite()); - if (count == itemStack.getCount()) { + int oldSize = remaining.getCount(); + remaining = HopperBlockEntity.addItem(blockEntity, into, remaining, direction.getOpposite()); + if (oldSize == remaining.getCount()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CraftingTableBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CraftingTableBlock.java.patch index 8cd3883d79a2..f865cb22f9f9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CraftingTableBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CraftingTableBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/CraftingTableBlock.java +++ b/net/minecraft/world/level/block/CraftingTableBlock.java -@@ -31,8 +_,9 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -33,8 +_,9 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CropBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CropBlock.java.patch index d30cd59871b4..073db8b0c7bf 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CropBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CropBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/CropBlock.java +++ b/net/minecraft/world/level/block/CropBlock.java -@@ -80,8 +_,25 @@ +@@ -81,8 +_,25 @@ int age = this.getAge(state); if (age < this.getMaxAge()) { float growthSpeed = getGrowthSpeed(this, level, pos); @@ -28,19 +28,19 @@ } } } -@@ -89,7 +_,7 @@ +@@ -90,7 +_,7 @@ - public void growCrops(Level level, BlockPos pos, BlockState state) { - int min = Math.min(this.getMaxAge(), this.getAge(state) + this.getBonemealAgeIncrease(level)); -- level.setBlock(pos, this.getStateForAge(min), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(min), Block.UPDATE_CLIENTS); // CraftBukkit + public void growCrops(final Level level, final BlockPos pos, final BlockState state) { + int age = Math.min(this.getMaxAge(), this.getAge(state) + this.getBonemealAgeIncrease(level)); +- level.setBlock(pos, this.getStateForAge(age), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(age), Block.UPDATE_CLIENTS); // CraftBukkit } - protected int getBonemealAgeIncrease(Level level) { -@@ -151,7 +_,8 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { + protected int getBonemealAgeIncrease(final Level level) { +@@ -159,7 +_,8 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { - if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().get(GameRules.MOB_GRIEFING))) { // CraftBukkit diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DaylightDetectorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DaylightDetectorBlock.java.patch index 8e8a4959038e..099ed53b359c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DaylightDetectorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DaylightDetectorBlock.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/level/block/DaylightDetectorBlock.java +++ b/net/minecraft/world/level/block/DaylightDetectorBlock.java -@@ -71,6 +_,7 @@ +@@ -70,6 +_,7 @@ - i = Mth.clamp(i, 0, 15); - if (state.getValue(POWER) != i) { -+ i = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(DaylightDetectorBlock.POWER), i).getNewCurrent(); // CraftBukkit - Call BlockRedstoneEvent - level.setBlock(pos, state.setValue(POWER, i), Block.UPDATE_ALL); + target = Mth.clamp(target, 0, 15); + if (state.getValue(POWER) != target) { ++ target = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(DaylightDetectorBlock.POWER), target).getNewCurrent(); // CraftBukkit - Call BlockRedstoneEvent + level.setBlock(pos, state.setValue(POWER, target), Block.UPDATE_ALL); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DecoratedPotBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DecoratedPotBlock.java.patch index 260767c050ff..debf5cc6f477 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DecoratedPotBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DecoratedPotBlock.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/DecoratedPotBlock.java +++ b/net/minecraft/world/level/block/DecoratedPotBlock.java -@@ -209,6 +_,11 @@ - protected void onProjectileHit(Level level, BlockState state, BlockHitResult hit, Projectile projectile) { - BlockPos blockPos = hit.getBlockPos(); - if (level instanceof ServerLevel serverLevel && projectile.mayInteract(serverLevel, blockPos) && projectile.mayBreak(serverLevel)) { +@@ -217,6 +_,11 @@ + protected void onProjectileHit(final Level level, final BlockState state, final BlockHitResult blockHit, final Projectile projectile) { + BlockPos pos = blockHit.getBlockPos(); + if (level instanceof ServerLevel serverLevel && projectile.mayInteract(serverLevel, pos) && projectile.mayBreak(serverLevel)) { + // CraftBukkit start - call EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockPos, this.getFluidState(state).createLegacyBlock())) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, pos, this.getFluidState(state).createLegacyBlock())) { + return; + } + // CraftBukkit end - level.setBlock(blockPos, state.setValue(CRACKED, true), Block.UPDATE_NONE); - level.destroyBlock(blockPos, true, projectile); + level.setBlock(pos, state.setValue(CRACKED, true), Block.UPDATE_NONE); + level.destroyBlock(pos, true, projectile); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DetectorRailBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DetectorRailBlock.java.patch index 865623c40a09..83c110f820b2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DetectorRailBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DetectorRailBlock.java.patch @@ -1,35 +1,35 @@ --- a/net/minecraft/world/level/block/DetectorRailBlock.java +++ b/net/minecraft/world/level/block/DetectorRailBlock.java -@@ -49,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -56,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide()) { if (!state.getValue(POWERED)) { this.checkPressed(level, pos, state); -@@ -79,6 +_,7 @@ +@@ -86,6 +_,7 @@ - private void checkPressed(Level level, BlockPos pos, BlockState state) { + private void checkPressed(final Level level, final BlockPos pos, final BlockState state) { if (this.canSurvive(state, level, pos)) { + if (!state.is(this)) { return; } // Paper - Fix some rails connecting improperly - boolean poweredValue = state.getValue(POWERED); - boolean flag = false; - List interactingMinecartOfType = this.getInteractingMinecartOfType(level, pos, AbstractMinecart.class, entity -> true); -@@ -86,6 +_,16 @@ - flag = true; + boolean wasPressed = state.getValue(POWERED); + boolean shouldBePressed = false; + List entities = this.getInteractingMinecartOfType(level, pos, AbstractMinecart.class, e -> true); +@@ -93,6 +_,16 @@ + shouldBePressed = true; } + // CraftBukkit start -+ if (poweredValue != flag) { ++ if (wasPressed != shouldBePressed) { + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + -+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, flag ? 15 : 0, flag ? 15 : 0); ++ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, shouldBePressed ? 15 : 0, shouldBePressed ? 15 : 0); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); + -+ flag = eventRedstone.getNewCurrent() > 0; ++ shouldBePressed = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end - if (flag && !poweredValue) { - BlockState blockState = state.setValue(POWERED, true); - level.setBlock(pos, blockState, Block.UPDATE_ALL); + if (shouldBePressed && !wasPressed) { + BlockState newState = state.setValue(POWERED, true); + level.setBlock(pos, newState, Block.UPDATE_ALL); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DiodeBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DiodeBlock.java.patch index df692dfea0dc..7a123063f7d6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DiodeBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DiodeBlock.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/block/DiodeBlock.java +++ b/net/minecraft/world/level/block/DiodeBlock.java @@ -56,8 +_,18 @@ - boolean poweredValue = state.getValue(POWERED); + boolean on = state.getValue(POWERED); boolean shouldTurnOn = this.shouldTurnOn(level, pos, state); - if (poweredValue && !shouldTurnOn) { + if (on && !shouldTurnOn) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) { + return; + } + // CraftBukkit end level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_CLIENTS); - } else if (!poweredValue) { + } else if (!on) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) { + return; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DirtPathBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DirtPathBlock.java.patch index bc73d1c956f9..3d58bc2d4783 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DirtPathBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DirtPathBlock.java.patch @@ -3,12 +3,12 @@ @@ -60,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + // CraftBukkit start - do not fade if the block is valid here + if (state.canSurvive(level, pos)) { + return; + } + // CraftBukkit end - FarmBlock.turnToDirt(null, state, level, pos); + FarmlandBlock.turnToDirt(null, state, level, pos); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DispenserBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DispenserBlock.java.patch index 190bf71c49a0..7bf41effb2eb 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DispenserBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DispenserBlock.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/world/level/block/DispenserBlock.java +++ b/net/minecraft/world/level/block/DispenserBlock.java -@@ -71,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { -- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof DispenserBlockEntity dispenserBlockEntity) { -- player.openMenu(dispenserBlockEntity); -+ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof DispenserBlockEntity dispenserBlockEntity && player.openMenu(dispenserBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation - player.awardStat(dispenserBlockEntity instanceof DropperBlockEntity ? Stats.INSPECT_DROPPER : Stats.INSPECT_DISPENSER); +@@ -75,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { +- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof DispenserBlockEntity dispenser) { +- player.openMenu(dispenser); ++ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof DispenserBlockEntity dispenser && player.openMenu(dispenser).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation + player.awardStat(dispenser instanceof DropperBlockEntity ? Stats.INSPECT_DROPPER : Stats.INSPECT_DISPENSER); } -@@ -87,17 +_,26 @@ - BlockSource blockSource = new BlockSource(level, pos, state, dispenserBlockEntity); - int randomSlot = dispenserBlockEntity.getRandomSlot(level.random); - if (randomSlot < 0) { +@@ -91,17 +_,26 @@ + BlockSource source = new BlockSource(level, pos, state, blockEntity); + int slot = blockEntity.getRandomSlot(level.getRandom()); + if (slot < 0) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(level, pos)) { // Paper - Add BlockFailedDispenseEvent level.levelEvent(LevelEvent.SOUND_DISPENSER_FAIL, pos, 0); - level.gameEvent(GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(dispenserBlockEntity.getBlockState())); + level.gameEvent(GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(blockEntity.getBlockState())); + } // Paper - Add BlockFailedDispenseEvent } else { - ItemStack item = dispenserBlockEntity.getItem(randomSlot); - DispenseItemBehavior dispenseMethod = this.getDispenseMethod(level, item); - if (dispenseMethod != DispenseItemBehavior.NOOP) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, item, randomSlot)) return; // Paper - Add BlockPreDispenseEvent - dispenserBlockEntity.setItem(randomSlot, dispenseMethod.dispense(blockSource, item)); + ItemStack itemStack = blockEntity.getItem(slot); + DispenseItemBehavior behavior = this.getDispenseMethod(level, itemStack); + if (behavior != DispenseItemBehavior.NOOP) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, itemStack, slot)) return; // Paper - Add BlockPreDispenseEvent + blockEntity.setItem(slot, behavior.dispense(source, itemStack)); } } } @@ -35,5 +35,5 @@ + } + // Paper end - Fix NPE with equippable and items without behavior - protected DispenseItemBehavior getDispenseMethod(Level level, ItemStack item) { - if (!item.isItemEnabled(level.enabledFeatures())) { + protected DispenseItemBehavior getDispenseMethod(final Level level, final ItemStack itemStack) { + if (!itemStack.isItemEnabled(level.enabledFeatures())) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch index 77f0acfcdd6f..5b6beae4a05d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/DoorBlock.java +++ b/net/minecraft/world/level/block/DoorBlock.java -@@ -221,9 +_,22 @@ - - @Override - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { -- boolean flag = level.hasNeighborSignal(pos) +@@ -225,9 +_,22 @@ + protected void neighborChanged( + final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston + ) { +- boolean signal = level.hasNeighborSignal(pos) - || level.hasNeighborSignal(pos.relative(state.getValue(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN)); -- if (!this.defaultBlockState().is(neighborBlock) && flag != state.getValue(POWERED)) { +- if (!this.defaultBlockState().is(block) && signal != state.getValue(POWERED)) { + // CraftBukkit start + BlockPos otherHalf = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN); + org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); @@ -21,8 +21,8 @@ + org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, oldPower, power); + event.callEvent(); + -+ boolean flag = event.getNewCurrent() > 0; ++ boolean signal = event.getNewCurrent() > 0; + // CraftBukkit end - if (flag != state.getValue(OPEN)) { - this.playSound(null, level, pos, flag); - level.gameEvent(null, flag ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos); + if (signal != state.getValue(OPEN)) { + this.playSound(null, level, pos, signal); + level.gameEvent(null, signal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch index 3416e7d85dbc..cfd5138462c3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch @@ -3,14 +3,14 @@ @@ -34,7 +_,12 @@ return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); } else { - BlockPos blockPos = pos.relative(directionGetter.apply(state)); -- BlockState blockState = level.getBlockState(blockPos); + BlockPos neighborPos = pos.relative(connectionResolver.apply(state)); +- BlockState neighbourState = level.getBlockState(neighborPos); + // Paper start - Don't load Chunks from Hoppers and other things -+ BlockState blockState = level.getBlockStateIfLoaded(blockPos); -+ if (blockState == null) { ++ BlockState neighbourState = level.getBlockStateIfLoaded(neighborPos); ++ if (neighbourState == null) { + return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); + } + // Paper end - Don't load Chunks from Hoppers and other things - if (blockState.is(state.getBlock())) { - DoubleBlockCombiner.BlockType blockType1 = doubleBlockTypeGetter.apply(blockState); - if (blockType1 != DoubleBlockCombiner.BlockType.SINGLE + if (neighbourState.is(state.getBlock())) { + DoubleBlockCombiner.BlockType neighbourType = typeResolver.apply(neighbourState); + if (neighbourType != DoubleBlockCombiner.BlockType.SINGLE diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DoublePlantBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DoublePlantBlock.java.patch index 0d4725287a6d..5c7d6de9859a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DoublePlantBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DoublePlantBlock.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/level/block/DoublePlantBlock.java +++ b/net/minecraft/world/level/block/DoublePlantBlock.java -@@ -109,11 +_,16 @@ +@@ -114,11 +_,17 @@ + final BlockState state, + final @Nullable BlockEntity blockEntity, + final ItemStack destroyedWith ++ , boolean includeDrops, boolean dropExp // Paper - fix drops not preventing stats/food exhaustion + ) { +- super.playerDestroy(level, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, destroyedWith); ++ super.playerDestroy(level, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, destroyedWith, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion; } - @Override -- public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) { -- super.playerDestroy(level, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, stack); -+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(level, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, stack, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion; - } - - protected static void preventDropFromBottomPart(Level level, BlockPos pos, BlockState state, Player player) { + protected static void preventDropFromBottomPart(final Level level, final BlockPos pos, final BlockState state, final Player player) { + // CraftBukkit start + if (((net.minecraft.server.level.ServerLevel)level).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(level, pos).isCancelled()) { // Paper + return; + } + // CraftBukkit end - DoubleBlockHalf doubleBlockHalf = state.getValue(HALF); - if (doubleBlockHalf == DoubleBlockHalf.UPPER) { - BlockPos blockPos = pos.below(); + DoubleBlockHalf part = state.getValue(HALF); + if (part == DoubleBlockHalf.UPPER) { + BlockPos bottomPos = pos.below(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch index ea38b8d064ea..e5cf4537b307 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/block/DragonEggBlock.java +++ b/net/minecraft/world/level/block/DragonEggBlock.java -@@ -55,6 +_,16 @@ - level.random.nextInt(16) - level.random.nextInt(16) - ); - if (level.getBlockState(blockPos).isAir() && worldBorder.isWithinBounds(blockPos) && !level.isOutsideBuildHeight(blockPos)) { +@@ -60,6 +_,16 @@ + && !level.getBlockState(testPos.below()).isAir() + && worldBorder.isWithinBounds(testPos) + && level.isInsideBuildHeight(testPos)) { + // CraftBukkit start + org.bukkit.block.Block from = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.block.Block to = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos); ++ org.bukkit.block.Block to = org.bukkit.craftbukkit.block.CraftBlock.at(level, testPos); + org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(from, to); + if (!event.callEvent()) { + return; + } + -+ blockPos = new BlockPos(event.getToBlock().getX(), event.getToBlock().getY(), event.getToBlock().getZ()); ++ testPos = new BlockPos(event.getToBlock().getX(), event.getToBlock().getY(), event.getToBlock().getZ()); + // CraftBukkit end if (level.isClientSide()) { - for (int i1 = 0; i1 < 128; i1++) { - double randomDouble = level.random.nextDouble(); + for (int j = 0; j < 128; j++) { + double d = random.nextDouble(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DriedGhastBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DriedGhastBlock.java.patch index f0247b5487b8..18cb2b81d438 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DriedGhastBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DriedGhastBlock.java.patch @@ -2,32 +2,32 @@ +++ b/net/minecraft/world/level/block/DriedGhastBlock.java @@ -104,10 +_,20 @@ - private void tickWaterlogged(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + private void tickWaterlogged(final BlockState state, final ServerLevel level, final BlockPos position, final RandomSource random) { if (!this.isReadyToSpawn(state)) { + // Paper start - Call BlockGrowEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, position, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS)) { + return; + } + // Paper end - Call BlockGrowEvent - level.playSound(null, pos, SoundEvents.DRIED_GHAST_TRANSITION, SoundSource.BLOCKS, 1.0F, 1.0F); -- level.setBlock(pos, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS); -+ // level.setBlock(pos, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS); // Paper - handled above - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); + level.playSound(null, position, SoundEvents.DRIED_GHAST_TRANSITION, SoundSource.BLOCKS, 1.0F, 1.0F); +- level.setBlock(position, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS); ++ // level.setBlock(position, state.setValue(HYDRATION_LEVEL, this.getHydrationLevel(state) + 1), Block.UPDATE_CLIENTS); // Paper - handled above + level.gameEvent(GameEvent.BLOCK_CHANGE, position, GameEvent.Context.of(state)); } else { + // Paper start - Call BlockFadeEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, position, state.getFluidState().createLegacyBlock()).isCancelled()) { + return; + } + // Paper end - Call BlockFadeEvent - this.spawnGhastling(level, pos, state); + this.spawnGhastling(level, position, state); } } @@ -121,7 +_,7 @@ - float yRot = Direction.getYRot(state.getValue(FACING)); - happyGhast.setYHeadRot(yRot); - happyGhast.snapTo(bottomCenter.x(), bottomCenter.y(), bottomCenter.z(), yRot, 0.0F); -- level.addFreshEntity(happyGhast); -+ level.addFreshEntity(happyGhast, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REHYDRATION); // Paper - spawn reason - level.playSound(null, happyGhast, SoundEvents.GHASTLING_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); + float blockRotation = Direction.getYRot(state.getValue(FACING)); + ghastling.setYHeadRot(blockRotation); + ghastling.snapTo(spawnAt.x(), spawnAt.y(), spawnAt.z(), blockRotation, 0.0F); +- level.addFreshEntity(ghastling); ++ level.addFreshEntity(ghastling, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REHYDRATION); // Paper - spawn reason + level.playSound(null, ghastling, SoundEvents.GHASTLING_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DropExperienceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DropExperienceBlock.java.patch index 6fbb433e7bfa..28c78bb336d4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DropExperienceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DropExperienceBlock.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/level/block/DropExperienceBlock.java +++ b/net/minecraft/world/level/block/DropExperienceBlock.java -@@ -31,8 +_,16 @@ +@@ -29,8 +_,16 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegate to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack tool, boolean dropExperience) { if (dropExperience) { -- this.tryDropExperience(level, pos, stack, this.xpRange); +- this.tryDropExperience(level, pos, tool, this.xpRange); - } -+ return this.tryDropExperience(level, pos, stack, this.xpRange); ++ return this.tryDropExperience(level, pos, tool, this.xpRange); + } + + return 0; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DropperBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DropperBlock.java.patch index 97d52b1a403e..6f97429c74c1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DropperBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DropperBlock.java.patch @@ -1,42 +1,40 @@ --- a/net/minecraft/world/level/block/DropperBlock.java +++ b/net/minecraft/world/level/block/DropperBlock.java @@ -53,6 +_,7 @@ - BlockSource blockSource = new BlockSource(level, pos, state, dispenserBlockEntity); - int randomSlot = dispenserBlockEntity.getRandomSlot(level.random); - if (randomSlot < 0) { + BlockSource source = new BlockSource(level, pos, state, blockEntity); + int slot = blockEntity.getRandomSlot(level.getRandom()); + if (slot < 0) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(level, pos)) // Paper - Add BlockFailedDispenseEvent level.levelEvent(LevelEvent.SOUND_DISPENSER_FAIL, pos, 0); } else { - ItemStack item = dispenserBlockEntity.getItem(randomSlot); -@@ -61,10 +_,29 @@ - Container containerAt = HopperBlockEntity.getContainerAt(level, pos.relative(direction)); - ItemStack itemStack; - if (containerAt == null) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, item, randomSlot)) return; // Paper - Add BlockPreDispenseEvent - itemStack = DISPENSE_BEHAVIOUR.dispense(blockSource, item); + ItemStack itemStack = blockEntity.getItem(slot); +@@ -61,10 +_,27 @@ + Container into = HopperBlockEntity.getContainerAt(level, pos.relative(direction)); + ItemStack remaining; + if (into == null) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, itemStack, slot)) return; // Paper - Add BlockPreDispenseEvent + remaining = DISPENSE_BEHAVIOUR.dispense(source, itemStack); } else { -- itemStack = HopperBlockEntity.addItem(dispenserBlockEntity, containerAt, item.copyWithCount(1), direction.getOpposite()); -- if (itemStack.isEmpty()) { +- remaining = HopperBlockEntity.addItem(blockEntity, into, itemStack.copyWithCount(1), direction.getOpposite()); +- if (remaining.isEmpty()) { + // CraftBukkit start - Fire event when pushing items into other inventories -+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); + + org.bukkit.inventory.Inventory destinationInventory; + // Have to special case large chests as they work oddly -+ if (containerAt instanceof net.minecraft.world.CompoundContainer compoundContainer) { ++ if (into instanceof net.minecraft.world.CompoundContainer compoundContainer) { + destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); + } else { -+ destinationInventory = containerAt.getOwner().getInventory(); ++ destinationInventory = into.getOwner().getInventory(); + } + -+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(dispenserBlockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); -+ level.getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); ++ if (!event.callEvent()) { + return; + } -+ itemStack = HopperBlockEntity.addItem(dispenserBlockEntity, containerAt, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction.getOpposite()); -+ if (event.getItem().equals(oitemstack) && itemStack.isEmpty()) { ++ remaining = HopperBlockEntity.addItem(blockEntity, into, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction.getOpposite()); ++ if (event.getItem().equals(oitemstack) && remaining.isEmpty()) { + // CraftBukkit end -+ - itemStack = item.copy(); - itemStack.shrink(1); + remaining = itemStack.copy(); + remaining.shrink(1); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch index b0a0bea9ebad..96a145af4719 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch @@ -1,30 +1,37 @@ --- a/net/minecraft/world/level/block/EndGatewayBlock.java +++ b/net/minecraft/world/level/block/EndGatewayBlock.java -@@ -89,10 +_,15 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -94,10 +_,15 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false) && !level.isClientSide() - && level.getBlockEntity(pos) instanceof TheEndGatewayBlockEntity theEndGatewayBlockEntity - && !theEndGatewayBlockEntity.isCoolingDown()) { + && level.getBlockEntity(pos) instanceof TheEndGatewayBlockEntity endGatewayBlockEntity + && !endGatewayBlockEntity.isCoolingDown()) { + // Paper start - call EntityPortalEnterEvent + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type + if (!event.callEvent()) return; + // Paper end - call EntityPortalEnterEvent entity.setAsInsidePortal(this, pos); - TheEndGatewayBlockEntity.triggerCooldown(level, pos, state, theEndGatewayBlockEntity); + TheEndGatewayBlockEntity.triggerCooldown(level, pos, state, endGatewayBlockEntity); } -@@ -106,9 +_,9 @@ +@@ -111,7 +_,7 @@ return null; } else { return entity instanceof ThrownEnderpearl -- ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET) -+ ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit +- ? new TeleportTransition(currentLevel, teleportPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET) ++ ? new TeleportTransition(currentLevel, teleportPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit : new TeleportTransition( -- level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET -+ level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY // CraftBukkit + currentLevel, + teleportPosition, +@@ -119,7 +_,8 @@ + 0.0F, + 0.0F, + Relative.union(Relative.DELTA, Relative.ROTATION), +- TeleportTransition.PLACE_PORTAL_TICKET ++ TeleportTransition.PLACE_PORTAL_TICKET, ++ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY // CraftBukkit ); } } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch index d9e3c4ce3361..920164481523 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch @@ -1,64 +1,64 @@ --- a/net/minecraft/world/level/block/EndPortalBlock.java +++ b/net/minecraft/world/level/block/EndPortalBlock.java -@@ -59,8 +_,15 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -66,8 +_,14 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false)) { + // CraftBukkit start - Entity in portal + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), org.bukkit.PortalType.ENDER); // Paper - add portal type -+ level.getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) return; // Paper - make cancellable ++ if (!event.callEvent()) return; // Paper - make cancellable + // CraftBukkit end - if (!level.isClientSide() && level.dimension() == Level.END && entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { -+ if (level.paperConfig().misc.disableEndCredits) {serverPlayer.seenCredits = true; return;} // Paper - Option to disable end credits - serverPlayer.showEndCredits(); + if (!level.isClientSide() && level.dimension() == Level.END && entity instanceof ServerPlayer player && !player.seenCredits) { ++ if (level.paperConfig().misc.disableEndCredits) {player.seenCredits = true; return;} // Paper - Option to disable end credits + player.showEndCredits(); } else { entity.setAsInsidePortal(this, pos); -@@ -72,7 +_,7 @@ - public @Nullable TeleportTransition getPortalDestination(ServerLevel level, Entity entity, BlockPos pos) { - LevelData.RespawnData respawnData = level.getRespawnData(); - ResourceKey resourceKey = level.dimension(); -- boolean flag = resourceKey == Level.END; -+ boolean flag = level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END; // CraftBukkit - SPIGOT-6152: send back to main overworld in custom ends - ResourceKey resourceKey1 = flag ? respawnData.dimension() : Level.END; - BlockPos blockPos = flag ? respawnData.pos() : ServerLevel.END_SPAWN_POINT; - ServerLevel level1 = level.getServer().getLevel(resourceKey1); -@@ -84,7 +_,7 @@ - float f1; - Set set; - if (!flag) { -- EndPlatformFeature.createEndPlatform(level1, BlockPos.containing(bottomCenter).below(), true); -+ EndPlatformFeature.createEndPlatform(level1, BlockPos.containing(bottomCenter).below(), true, entity); // CraftBukkit - f = Direction.WEST.toYRot(); - f1 = 0.0F; - set = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); -@@ -96,15 +_,24 @@ - f1 = respawnData.pitch(); - set = Relative.union(Relative.DELTA, Relative.ROTATION); +@@ -78,8 +_,7 @@ + @Override + public @Nullable TeleportTransition getPortalDestination(final ServerLevel currentLevel, final Entity entity, final BlockPos portalEntryPos) { + LevelData.RespawnData respawnData = currentLevel.getRespawnData(); +- ResourceKey currentDimension = currentLevel.dimension(); +- boolean fromEnd = currentDimension == Level.END; ++ boolean fromEnd = currentLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END; // CraftBukkit - SPIGOT-6152: send back to main overworld in custom ends + ResourceKey newDimension = fromEnd ? respawnData.dimension() : Level.END; + BlockPos spawnBlockPos = fromEnd ? respawnData.pos() : ServerLevel.END_SPAWN_POINT; + ServerLevel newLevel = currentLevel.getServer().getLevel(newDimension); +@@ -91,7 +_,7 @@ + float xRot; + Set relatives; + if (!fromEnd) { +- EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true); ++ EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true, entity); // CraftBukkit + yRot = Direction.WEST.toYRot(); + xRot = 0.0F; + relatives = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); +@@ -103,15 +_,26 @@ + xRot = respawnData.pitch(); + relatives = Relative.union(Relative.DELTA, Relative.ROTATION); if (entity instanceof ServerPlayer serverPlayer) { - return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING); + return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL); // CraftBukkit } - bottomCenter = entity.adjustSpawnLocation(level1, blockPos).getBottomCenter(); + spawnPos = entity.adjustSpawnLocation(newLevel, spawnBlockPos).getBottomCenter(); } -- return new TeleportTransition( -- level1, bottomCenter, Vec3.ZERO, f, f1, set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) -- ); + // CraftBukkit start -+ set.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation -+ float absoluteYaw = !flag ? f : entity.getYRot() + f; -+ float absolutePitch = entity.getXRot() + f1; -+ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(bottomCenter, level1, absoluteYaw, absolutePitch), org.bukkit.PortalType.ENDER, 0, 0); ++ relatives.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation ++ float absoluteYaw = !fromEnd ? yRot : entity.getYRot() + yRot; ++ float absolutePitch = entity.getXRot() + xRot; ++ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, newLevel, absoluteYaw, absolutePitch), org.bukkit.PortalType.ENDER, 0, 0); + if (result == null) { + return null; + } + org.bukkit.Location to = result.to(); + -+ return new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL); + return new TeleportTransition( +- newLevel, spawnPos, Vec3.ZERO, yRot, xRot, relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) ++ ((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL + ); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch index 30b8c15a5292..80ee1af7526e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch @@ -1,26 +1,22 @@ --- a/net/minecraft/world/level/block/EnderChestBlock.java +++ b/net/minecraft/world/level/block/EnderChestBlock.java -@@ -78,16 +_,17 @@ - PlayerEnderChestContainer enderChestInventory = player.getEnderChestInventory(); - if (enderChestInventory != null && level.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChestBlockEntity) { - BlockPos blockPos = pos.above(); -- if (level.getBlockState(blockPos).isRedstoneConductor(level, blockPos)) { -+ if (level.getBlockState(blockPos).isRedstoneConductor(level, blockPos)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic +@@ -82,14 +_,15 @@ + PlayerEnderChestContainer container = player.getEnderChestInventory(); + if (container != null && level.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChest) { + BlockPos above = pos.above(); +- if (level.getBlockState(above).isRedstoneConductor(level, above)) { ++ if (level.getBlockState(above).isRedstoneConductor(level, above)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic return InteractionResult.SUCCESS; } else { - if (level instanceof ServerLevel serverLevel) { -- enderChestInventory.setActiveChest(enderChestBlockEntity); +- container.setActiveChest(enderChest); - player.openMenu( -- new SimpleMenuProvider( -- (containerId, playerInventory, player1) -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE -- ) +- new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE) - ); + // Paper start - Fix InventoryOpenEvent cancellation - moved up; -+ enderChestInventory.setActiveChest(enderChestBlockEntity); // Needs to happen before ChestMenu.threeRows as it is required for opening animations ++ container.setActiveChest(enderChest); // Needs to happen before ChestMenu.threeRows as it is required for opening animations + if (level instanceof ServerLevel serverLevel && player.openMenu( -+ new SimpleMenuProvider( -+ (containerId, playerInventory, player1) -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE -+ ) ++ new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE) + ).isPresent()) { + // Paper end - Fix InventoryOpenEvent cancellation - moved up; player.awardStat(Stats.OPEN_ENDERCHEST); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EyeblossomBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EyeblossomBlock.java.patch index 729776be28cf..163dc5621cb9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EyeblossomBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EyeblossomBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/EyeblossomBlock.java +++ b/net/minecraft/world/level/block/EyeblossomBlock.java -@@ -100,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -106,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide() && level.getDifficulty() != Difficulty.PEACEFUL diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FarmlandBlock.java.patch similarity index 51% rename from paper-server/patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/FarmlandBlock.java.patch index 145e5b929c5c..e9491079cab5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FarmlandBlock.java.patch @@ -1,49 +1,49 @@ ---- a/net/minecraft/world/level/block/FarmBlock.java -+++ b/net/minecraft/world/level/block/FarmBlock.java -@@ -95,31 +_,59 @@ +--- a/net/minecraft/world/level/block/FarmlandBlock.java ++++ b/net/minecraft/world/level/block/FarmlandBlock.java +@@ -94,31 +_,59 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - int moistureValue = state.getValue(MOISTURE); -+ if (moistureValue > 0 && level.paperConfig().tickRates.wetFarmland != 1 && (level.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks -+ if (moistureValue == 0 && level.paperConfig().tickRates.dryFarmland != 1 && (level.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + int moisture = state.getValue(MOISTURE); ++ if (moisture > 0 && level.paperConfig().tickRates.wetFarmland != 1 && (level.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks ++ if (moisture == 0 && level.paperConfig().tickRates.dryFarmland != 1 && (level.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks if (!isNearWater(level, pos) && !level.isRainingAt(pos.above())) { - if (moistureValue > 0) { -- level.setBlock(pos, state.setValue(MOISTURE, moistureValue - 1), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, state.setValue(MOISTURE, moistureValue - 1), Block.UPDATE_CLIENTS); // CraftBukkit + if (moisture > 0) { +- level.setBlock(pos, state.setValue(MOISTURE, moisture - 1), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, state.setValue(MOISTURE, moisture - 1), Block.UPDATE_CLIENTS); // CraftBukkit } else if (!shouldMaintainFarmland(level, pos)) { turnToDirt(null, state, level, pos); } - } else if (moistureValue < 7) { + } else if (moisture < 7) { - level.setBlock(pos, state.setValue(MOISTURE, 7), Block.UPDATE_CLIENTS); + org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, state.setValue(MOISTURE, 7), Block.UPDATE_CLIENTS); // CraftBukkit } } @Override - public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, double fallDistance) { + public void fallOn(final Level level, final BlockState state, final BlockPos pos, final Entity entity, final double fallDistance) { + super.fallOn(level, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. if (level instanceof ServerLevel serverLevel - && level.random.nextFloat() < fallDistance - 0.5 + && level.getRandom().nextFloat() < fallDistance - 0.5 && entity instanceof LivingEntity && (entity instanceof Player || serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { -+ // CraftBukkit start - Interact soil -+ org.bukkit.event.Cancellable cancellable; -+ if (entity instanceof Player) { -+ cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((Player) entity, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null); -+ } else { -+ cancellable = new org.bukkit.event.entity.EntityInteractEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)); -+ level.getCraftServer().getPluginManager().callEvent((org.bukkit.event.entity.EntityInteractEvent) cancellable); -+ } ++ // CraftBukkit start - Interact soil ++ org.bukkit.event.Cancellable cancellable; ++ if (entity instanceof Player) { ++ cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent((Player) entity, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null); ++ } else { ++ cancellable = new org.bukkit.event.entity.EntityInteractEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)); ++ level.getCraftServer().getPluginManager().callEvent((org.bukkit.event.entity.EntityInteractEvent) cancellable); ++ } + -+ if (cancellable.isCancelled()) { -+ return; -+ } ++ if (cancellable.isCancelled()) { ++ return; ++ } + -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { -+ return; -+ } -+ // CraftBukkit end ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { ++ return; ++ } ++ // CraftBukkit end turnToDirt(entity, state, level, pos); } @@ -51,22 +51,22 @@ + // super.fallOn(level, state, pos, entity, fallDistance); // CraftBukkit - moved up } - public static void turnToDirt(@Nullable Entity entity, BlockState state, Level level, BlockPos pos) { + public static void turnToDirt(final @Nullable Entity sourceEntity, final BlockState state, final Level level, final BlockPos pos) { + // CraftBukkit start -+ if (entity == null) { ++ if (sourceEntity == null) { + if (org.bukkit.craftbukkit.event.CraftEventFactory + .callBlockFadeEvent(level, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) { + return; + } + } + // CraftBukkit end - BlockState blockState = pushEntitiesUp(state, Blocks.DIRT.defaultBlockState(), level, pos); - level.setBlockAndUpdate(pos, blockState); - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, blockState)); -@@ -130,13 +_,27 @@ + BlockState newState = pushEntitiesUp(state, Blocks.DIRT.defaultBlockState(), level, pos); + level.setBlockAndUpdate(pos, newState); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); +@@ -129,13 +_,27 @@ } - private static boolean isNearWater(LevelReader level, BlockPos pos) { + private static boolean isNearWater(final LevelReader level, final BlockPos pos) { - for (BlockPos blockPos : BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4))) { - if (level.getFluidState(blockPos).is(FluidTags.WATER)) { - return true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FenceGateBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FenceGateBlock.java.patch index c9a1747db626..aadfc7e392fe 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FenceGateBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FenceGateBlock.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/block/FenceGateBlock.java +++ b/net/minecraft/world/level/block/FenceGateBlock.java -@@ -199,6 +_,17 @@ - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +@@ -188,6 +_,17 @@ + ) { if (!level.isClientSide()) { - boolean hasNeighborSignal = level.hasNeighborSignal(pos); + boolean hasPower = level.hasNeighborSignal(pos); + // CraftBukkit start + boolean oldPowered = state.getValue(FenceGateBlock.POWERED); -+ if (oldPowered != hasNeighborSignal) { -+ int newPower = hasNeighborSignal ? 15 : 0; ++ if (oldPowered != hasPower) { ++ int newPower = hasPower ? 15 : 0; + int oldPower = oldPowered ? 15 : 0; + org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, oldPower, newPower); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); -+ hasNeighborSignal = eventRedstone.getNewCurrent() > 0; ++ hasPower = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end - if (state.getValue(POWERED) != hasNeighborSignal) { - level.setBlock(pos, state.setValue(POWERED, hasNeighborSignal).setValue(OPEN, hasNeighborSignal), Block.UPDATE_CLIENTS); - if (state.getValue(OPEN) != hasNeighborSignal) { + if (state.getValue(POWERED) != hasPower) { + level.setBlock(pos, state.setValue(POWERED, hasPower).setValue(OPEN, hasPower), Block.UPDATE_CLIENTS); + if (state.getValue(OPEN) != hasPower) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FireBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FireBlock.java.patch index eb63a4c8835e..c4b2256bb2fd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FireBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FireBlock.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/level/block/FireBlock.java +++ b/net/minecraft/world/level/block/FireBlock.java @@ -99,7 +_,25 @@ - BlockState neighborState, - RandomSource random + final BlockState neighbourState, + final RandomSource random ) { - return this.canSurvive(state, level, pos) ? this.getStateWithAge(level, pos, state.getValue(AGE)) : Blocks.AIR.defaultBlockState(); + // CraftBukkit start -+ if (!(level instanceof ServerLevel)) return this.canSurvive(state, level, pos) ? (BlockState) this.getStateWithAge(level, pos, (Integer) state.getValue(FireBlock.AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation ++ if (!(level instanceof ServerLevel)) return this.canSurvive(state, level, pos) ? this.getStateWithAge(level, pos, state.getValue(AGE)) : Blocks.AIR.defaultBlockState(); // Paper - don't fire events in world generation + if (!this.canSurvive(state, level, pos)) { + // Suppress during worldgen -+ if (!(level instanceof Level world1)) { ++ if (!(level instanceof Level world)) { + return Blocks.AIR.defaultBlockState(); + } -+ org.bukkit.craftbukkit.block.CraftBlockState blockState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(world1, pos); -+ blockState.setData(Blocks.AIR.defaultBlockState()); ++ org.bukkit.craftbukkit.block.CraftBlockState snapshot = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(world, pos); ++ snapshot.setBlock(Blocks.AIR.defaultBlockState()); + -+ org.bukkit.event.block.BlockFadeEvent event = new org.bukkit.event.block.BlockFadeEvent(blockState.getBlock(), blockState); -+ world1.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockFadeEvent event = new org.bukkit.event.block.BlockFadeEvent(snapshot.getBlock(), snapshot); ++ world.getCraftServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { -+ return blockState.getHandle(); ++ return snapshot.getHandle(); + } + } -+ return this.getStateWithAge(level, pos, (Integer) state.getValue(FireBlock.AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation" ++ return this.getStateWithAge(level, pos, state.getValue(AGE)); // Paper - don't fire events in world generation; diff on change, see "don't fire events in world generation" + // CraftBukkit end } @@ -30,8 +30,8 @@ @@ -139,17 +_,17 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { -- level.scheduleTick(pos, this, getFireTickDelay(level.random)); + protected void tick(BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { +- level.scheduleTick(pos, this, getFireTickDelay(level.getRandom())); + level.scheduleTick(pos, this, getFireTickDelay(level)); // Paper - Add fire-tick-delay option if (level.canSpreadFireAround(pos)) { if (!state.canSurvive(level, pos)) { @@ -39,19 +39,19 @@ + this.fireExtinguished(level, pos); // CraftBukkit - invalid place location } - BlockState blockState = level.getBlockState(pos.below()); - boolean isTag = blockState.is(level.dimensionType().infiniburn()); - int ageValue = state.getValue(AGE); - if (!isTag && level.isRaining() && this.isNearRain(level, pos) && random.nextFloat() < 0.2F + ageValue * 0.03F) { + BlockState belowState = level.getBlockState(pos.below()); + boolean infiniBurn = belowState.is(level.dimensionType().infiniburn()); + int age = state.getValue(AGE); + if (!infiniBurn && level.isRaining() && this.isNearRain(level, pos) && random.nextFloat() < 0.2F + age * 0.03F) { - level.removeBlock(pos, false); + this.fireExtinguished(level, pos); // CraftBukkit - extinguished by rain } else { - int min = Math.min(15, ageValue + random.nextInt(3) / 2); - if (ageValue != min) { + int newAge = Math.min(15, age + random.nextInt(3) / 2); + if (age != newAge) { @@ -161,26 +_,28 @@ if (!this.isValidFireLocation(level, pos)) { - BlockPos blockPos = pos.below(); - if (!level.getBlockState(blockPos).isFaceSturdy(level, blockPos, Direction.UP) || ageValue > 3) { + BlockPos below = pos.below(); + if (!level.getBlockState(below).isFaceSturdy(level, below, Direction.UP) || age > 3) { - level.removeBlock(pos, false); + this.fireExtinguished(level, pos); // CraftBukkit } @@ -59,44 +59,44 @@ return; } - if (ageValue == 15 && random.nextInt(4) == 0 && !this.canBurn(level.getBlockState(pos.below()))) { + if (age == 15 && random.nextInt(4) == 0 && !this.canBurn(level.getBlockState(pos.below()))) { - level.removeBlock(pos, false); + this.fireExtinguished(level, pos); // CraftBukkit return; } } - boolean value = level.environmentAttributes().getValue(EnvironmentAttributes.INCREASED_FIRE_BURNOUT, pos); - int i = value ? -50 : 0; -- this.checkBurnOut(level, pos.east(), 300 + i, random, ageValue); -- this.checkBurnOut(level, pos.west(), 300 + i, random, ageValue); -- this.checkBurnOut(level, pos.below(), 250 + i, random, ageValue); -- this.checkBurnOut(level, pos.above(), 250 + i, random, ageValue); -- this.checkBurnOut(level, pos.north(), 300 + i, random, ageValue); -- this.checkBurnOut(level, pos.south(), 300 + i, random, ageValue); + boolean increasedBurnout = level.environmentAttributes().getValue(EnvironmentAttributes.INCREASED_FIRE_BURNOUT, pos); + int extra = increasedBurnout ? -50 : 0; +- this.checkBurnOut(level, pos.east(), 300 + extra, random, age); +- this.checkBurnOut(level, pos.west(), 300 + extra, random, age); +- this.checkBurnOut(level, pos.below(), 250 + extra, random, age); +- this.checkBurnOut(level, pos.above(), 250 + extra, random, age); +- this.checkBurnOut(level, pos.north(), 300 + extra, random, age); +- this.checkBurnOut(level, pos.south(), 300 + extra, random, age); + // CraftBukkit start - add source blockPos to burn calls -+ this.checkBurnOut(level, pos.east(), 300 + i, random, ageValue, pos); -+ this.checkBurnOut(level, pos.west(), 300 + i, random, ageValue, pos); -+ this.checkBurnOut(level, pos.below(), 250 + i, random, ageValue, pos); -+ this.checkBurnOut(level, pos.above(), 250 + i, random, ageValue, pos); -+ this.checkBurnOut(level, pos.north(), 300 + i, random, ageValue, pos); -+ this.checkBurnOut(level, pos.south(), 300 + i, random, ageValue, pos); ++ this.checkBurnOut(level, pos.east(), 300 + extra, random, age, pos); ++ this.checkBurnOut(level, pos.west(), 300 + extra, random, age, pos); ++ this.checkBurnOut(level, pos.below(), 250 + extra, random, age, pos); ++ this.checkBurnOut(level, pos.above(), 250 + extra, random, age, pos); ++ this.checkBurnOut(level, pos.north(), 300 + extra, random, age, pos); ++ this.checkBurnOut(level, pos.south(), 300 + extra, random, age, pos); + // CraftBukkit end - add source blockPos to burn calls - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + BlockPos.MutableBlockPos testPos = new BlockPos.MutableBlockPos(); - for (int i1 = -1; i1 <= 1; i1++) { + for (int xx = -1; xx <= 1; xx++) { @@ -202,7 +_,15 @@ - if (i5 > 0 && random.nextInt(i4) <= i5 && (!level.isRaining() || !this.isNearRain(level, mutableBlockPos))) { - int min1 = Math.min(15, ageValue + random.nextInt(5) / 4); -- level.setBlock(mutableBlockPos, this.getStateWithAge(level, mutableBlockPos, min1), Block.UPDATE_ALL); + if (odds > 0 && random.nextInt(rate) <= odds && (!level.isRaining() || !this.isNearRain(level, testPos))) { + int spreadAge = Math.min(15, age + random.nextInt(5) / 4); +- level.setBlock(testPos, this.getStateWithAge(level, testPos, spreadAge), Block.UPDATE_ALL); + // CraftBukkit start - Call to stop spread of fire -+ if (!level.getBlockState(mutableBlockPos).is(Blocks.FIRE)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, mutableBlockPos, pos).isCancelled()) { ++ if (!level.getBlockState(testPos).is(Blocks.FIRE)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, testPos, pos).isCancelled()) { + continue; + } + -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, mutableBlockPos, this.getStateWithAge(level, mutableBlockPos, min1), UPDATE_ALL); // CraftBukkit ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, testPos, this.getStateWithAge(level, testPos, spreadAge), UPDATE_ALL); // CraftBukkit + } + // CraftBukkit end } @@ -106,11 +106,11 @@ : this.igniteOdds.getInt(state.getBlock()); } -- private void checkBurnOut(Level level, BlockPos pos, int chance, RandomSource random, int age) { -+ private void checkBurnOut(Level level, BlockPos pos, int chance, RandomSource random, int age, BlockPos sourcePos) { // CraftBukkit add sourcePos - int burnOdds = this.getBurnOdds(level.getBlockState(pos)); - if (random.nextInt(chance) < burnOdds) { - BlockState blockState = level.getBlockState(pos); +- private void checkBurnOut(final Level level, final BlockPos pos, final int chance, final RandomSource random, final int age) { ++ private void checkBurnOut(final Level level, final BlockPos pos, final int chance, final RandomSource random, final int age, final BlockPos sourcePos) { // CraftBukkit add sourcePos + int odds = this.getBurnOdds(level.getBlockState(pos)); + if (random.nextInt(chance) < odds) { + BlockState oldState = level.getBlockState(pos); + + // CraftBukkit start + org.bukkit.block.Block burnBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); @@ -121,19 +121,19 @@ + return; + } + -+ if (blockState.getBlock() instanceof TntBlock && !org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.FIRE, null, sourcePos)) { ++ if (oldState.getBlock() instanceof TntBlock && !org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.FIRE, null, sourcePos)) { + return; + } + // CraftBukkit end if (random.nextInt(age + 10) < 5 && !level.isRainingAt(pos)) { - int min = Math.min(age + random.nextInt(5) / 4, 15); - level.setBlock(pos, this.getStateWithAge(level, pos, min), Block.UPDATE_ALL); + int newAge = Math.min(age + random.nextInt(5) / 4, 15); + level.setBlock(pos, this.getStateWithAge(level, pos, newAge), Block.UPDATE_ALL); } else { - level.removeBlock(pos, false); -+ if (!blockState.is(Blocks.TNT)) level.removeBlock(pos, false); // Paper - TNTPrimeEvent; We might be cancelling it below, move the setAir down ++ if (!oldState.is(Blocks.TNT)) level.removeBlock(pos, false); // Paper - TNTPrimeEvent; We might be cancelling it below, move the setAir down } - Block block = blockState.getBlock(); + Block block = oldState.getBlock(); if (block instanceof TntBlock) { + // Paper start - TNTPrimeEvent + org.bukkit.block.Block tntBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); @@ -145,23 +145,24 @@ TntBlock.prime(level, pos); } } -@@ -287,13 +_,14 @@ +@@ -287,13 +_,15 @@ } @Override -- protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { +- protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { - super.onPlace(state, level, pos, oldState, movedByPiston); -- level.scheduleTick(pos, this, getFireTickDelay(level.random)); -+ protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston, net.minecraft.world.item.context.UseOnContext context) { +- level.scheduleTick(pos, this, getFireTickDelay(level.getRandom())); ++ // CraftBukkit start ++ protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston, final net.minecraft.world.item.context.UseOnContext context) { + super.onPlace(state, level, pos, oldState, movedByPiston, context); + // CraftBukkit end + level.scheduleTick(pos, this, FireBlock.getFireTickDelay(level)); // Paper - Add fire-tick-delay option } -- private static int getFireTickDelay(RandomSource random) { +- private static int getFireTickDelay(final RandomSource random) { - return 30 + random.nextInt(10); -+ private static int getFireTickDelay(Level level) { // Paper - Add fire-tick-delay option -+ return level.paperConfig().environment.fireTickDelay + level.random.nextInt(10); // Paper - Add fire-tick-delay option ++ private static int getFireTickDelay(final Level level) { // Paper - Add fire-tick-delay option ++ return level.paperConfig().environment.fireTickDelay + level.getRandom().nextInt(10); // Paper - Add fire-tick-delay option } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch index 6bd8c0239747..34e617023453 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/FlowerPotBlock.java +++ b/net/minecraft/world/level/block/FlowerPotBlock.java -@@ -67,6 +_,18 @@ +@@ -72,6 +_,18 @@ } else if (!this.isEmpty()) { return InteractionResult.CONSUME; } else { + // Paper start - Add PlayerFlowerPotManipulateEvent + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack); ++ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemStack); + + io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true); + if (!event.callEvent()) { @@ -16,13 +16,13 @@ + return InteractionResult.CONSUME; + } + // Paper end - Add PlayerFlowerPotManipulateEvent - level.setBlock(pos, blockState, Block.UPDATE_ALL); + level.setBlock(pos, newContents, Block.UPDATE_ALL); level.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); player.awardStat(Stats.POT_FLOWER); -@@ -81,6 +_,18 @@ +@@ -88,6 +_,18 @@ return InteractionResult.CONSUME; } else { - ItemStack itemStack = new ItemStack(this.potted); + ItemStack plant = new ItemStack(this.potted); + // Paper start - Add PlayerFlowerPotManipulateEvent + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + org.bukkit.inventory.ItemStack pottedStack = new org.bukkit.inventory.ItemStack(org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.potted)); @@ -35,6 +35,6 @@ + return InteractionResult.PASS; + } + // Paper end - Add PlayerFlowerPotManipulateEvent - if (!player.addItem(itemStack)) { - player.drop(itemStack, false); + if (!player.addItem(plant)) { + player.drop(plant, false); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FrogspawnBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FrogspawnBlock.java.patch index d00e1897c1c7..86a07210ae37 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FrogspawnBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FrogspawnBlock.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/level/block/FrogspawnBlock.java +++ b/net/minecraft/world/level/block/FrogspawnBlock.java -@@ -90,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -99,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity.getType().equals(EntityType.FALLING_BLOCK)) { + if (entity.is(EntityType.FALLING_BLOCK)) { this.destroyBlock(level, pos); } -@@ -102,6 +_,11 @@ +@@ -111,6 +_,11 @@ } - private void hatchFrogspawn(ServerLevel level, BlockPos pos, RandomSource random) { + private void hatchFrogspawn(final ServerLevel level, final BlockPos pos, final RandomSource random) { + // Paper start - Call BlockFadeEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { + return; @@ -20,9 +20,9 @@ this.destroyBlock(level, pos); level.playSound(null, pos, SoundEvents.FROGSPAWN_HATCH, SoundSource.BLOCKS, 1.0F, 1.0F); this.spawnTadpoles(level, pos, random); -@@ -122,7 +_,7 @@ - int randomInt1 = random.nextInt(1, 361); - tadpole.snapTo(d, pos.getY() - 0.5, d1, randomInt1, 0.0F); +@@ -131,7 +_,7 @@ + int yRot = random.nextInt(1, 361); + tadpole.snapTo(xPos, pos.getY() - 0.5, zPos, yRot, 0.0F); tadpole.setPersistenceRequired(); - level.addFreshEntity(tadpole); + level.addFreshEntity(tadpole, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // Paper - use correct spawn reason diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FrostedIceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FrostedIceBlock.java.patch index 1ad12aa315df..62998358c5a5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FrostedIceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FrostedIceBlock.java.patch @@ -3,17 +3,17 @@ @@ -43,6 +_,7 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + if (!level.paperConfig().environment.frostedIce.enabled) return; // Paper - Frosted ice options if (random.nextInt(3) == 0 || this.fewerNeigboursThan(level, pos, 4)) { - int i = level.dimension() == Level.END ? level.getBrightness(LightLayer.BLOCK, pos) : level.getMaxLocalRawBrightness(pos); - if (i > 11 - state.getValue(AGE) - state.getLightBlock() && this.slightlyMelt(state, level, pos)) { + int brightness = level.dimension() == Level.END ? level.getBrightness(LightLayer.BLOCK, pos) : level.getMaxLocalRawBrightness(pos); + if (brightness > 11 - state.getValue(AGE) - state.getLightDampening() && this.slightlyMelt(state, level, pos)) { @@ -52,7 +_,7 @@ - mutableBlockPos.setWithOffset(pos, direction); - BlockState blockState = level.getBlockState(mutableBlockPos); - if (blockState.is(this) && !this.slightlyMelt(blockState, level, mutableBlockPos)) { -- level.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, 20, 40)); -+ level.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, level.paperConfig().environment.frostedIce.delay.min, level.paperConfig().environment.frostedIce.delay.max)); // Paper - Frosted ice options + neighborPos.setWithOffset(pos, direction); + BlockState neighbour = level.getBlockState(neighborPos); + if (neighbour.is(this) && !this.slightlyMelt(neighbour, level, neighborPos)) { +- level.scheduleTick(neighborPos, this, Mth.nextInt(random, 20, 40)); ++ level.scheduleTick(neighborPos, this, Mth.nextInt(random, level.paperConfig().environment.frostedIce.delay.min, level.paperConfig().environment.frostedIce.delay.max)); // Paper - Frosted ice options } } @@ -25,4 +25,4 @@ + level.scheduleTick(pos, this, Mth.nextInt(random, level.paperConfig().environment.frostedIce.delay.min, level.paperConfig().environment.frostedIce.delay.max)); // Paper - Frosted ice options } - private boolean slightlyMelt(BlockState state, Level level, BlockPos pos) { + private boolean slightlyMelt(final BlockState state, final Level level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FungusBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FungusBlock.java.patch deleted file mode 100644 index 1e6860b8a177..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FungusBlock.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/world/level/block/FungusBlock.java -+++ b/net/minecraft/world/level/block/FungusBlock.java -@@ -72,6 +_,17 @@ - - @Override - public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { -- this.getFeature(level).ifPresent(holder -> holder.value().place(level, level.getChunkSource().getGenerator(), random, pos)); -+ this.getFeature(level) -+ // CraftBukkit start -+ .map((value) -> { -+ if (this == Blocks.WARPED_FUNGUS) { -+ SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS; -+ } else if (this == Blocks.CRIMSON_FUNGUS) { -+ SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS; -+ } -+ return value; -+ }) -+ .ifPresent(holder -> holder.value().place(level, level.getChunkSource().getGenerator(), random, pos)); -+ // CraftBukkit end - } - } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FurnaceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FurnaceBlock.java.patch index 7388ee1d652a..3b49693c82d2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FurnaceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FurnaceBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/FurnaceBlock.java @@ -44,8 +_,7 @@ @Override - protected void openContainer(Level level, BlockPos pos, Player player) { + protected void openContainer(final Level level, final BlockPos pos, final Player player) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof FurnaceBlockEntity) { - player.openMenu((MenuProvider)blockEntity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/GrindstoneBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/GrindstoneBlock.java.patch index 07b756010a5e..b7412f121b0b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/GrindstoneBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/GrindstoneBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/GrindstoneBlock.java +++ b/net/minecraft/world/level/block/GrindstoneBlock.java -@@ -72,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -74,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { - if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (!level.isClientSide() && player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch index 0a540390f89f..e2922b98ff49 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/GrowingPlantHeadBlock.java +++ b/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -@@ -44,13 +_,31 @@ +@@ -48,13 +_,31 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { - if (state.getValue(AGE) < 25 && random.nextDouble() < this.growPerTickProbability) { + // Spigot start + int modifier = 100; @@ -16,21 +16,21 @@ + } else if (this == Blocks.CAVE_VINES) { + modifier = level.spigotConfig.caveVinesModifier; + } -+ if (state.getValue(AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution ++ if (state.getValue(AGE) < 25 && random.nextDouble() < ((modifier / 100.0) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution + // Spigot end - BlockPos blockPos = pos.relative(this.growthDirection); - if (this.canGrowInto(level.getBlockState(blockPos))) { -- level.setBlockAndUpdate(blockPos, this.getGrowIntoState(state, level.random)); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, this.getGrowIntoState(state, level.random, level), Block.UPDATE_ALL); // CraftBukkit // Paper - Fix Spigot growth modifiers + BlockPos growthPos = pos.relative(this.growthDirection); + if (this.canGrowInto(level.getBlockState(growthPos))) { +- level.setBlockAndUpdate(growthPos, this.getGrowIntoState(state, level.getRandom())); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, growthPos, this.getGrowIntoState(state, level.getRandom(), level), Block.UPDATE_ALL); // CraftBukkit // Paper - Fix Spigot growth modifiers } } } + + // Paper start - Fix Spigot growth modifiers -+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) { ++ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @org.jspecify.annotations.Nullable Level level) { + return this.getGrowIntoState(state, random); + } + // Paper end - Fix Spigot growth modifiers - protected BlockState getGrowIntoState(BlockState state, RandomSource random) { - return state.cycle(AGE); + protected BlockState getGrowIntoState(final BlockState growFromState, final RandomSource random) { + return growFromState.cycle(AGE); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/HoneyBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/HoneyBlock.java.patch index 56d52b467968..ca996ad35af6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/HoneyBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/HoneyBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/HoneyBlock.java +++ b/net/minecraft/world/level/block/HoneyBlock.java -@@ -62,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -70,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (this.isSlidingDown(pos, entity)) { this.maybeDoSlideAchievement(entity, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/HopperBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/HopperBlock.java.patch index 8e160a4c11cb..7b243614f309 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/HopperBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/HopperBlock.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/block/HopperBlock.java +++ b/net/minecraft/world/level/block/HopperBlock.java -@@ -102,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { -- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof HopperBlockEntity hopperBlockEntity) { -- player.openMenu(hopperBlockEntity); -+ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof HopperBlockEntity hopperBlockEntity && player.openMenu(hopperBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation +@@ -106,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { +- if (!level.isClientSide() && level.getBlockEntity(pos) instanceof HopperBlockEntity hopper) { +- player.openMenu(hopper); ++ if (!level.isClientSide() && level.getBlockEntity(pos) instanceof HopperBlockEntity hopper && player.openMenu(hopper).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation player.awardStat(Stats.INSPECT_HOPPER); } -@@ -154,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -167,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent BlockEntity blockEntity = level.getBlockEntity(pos); if (blockEntity instanceof HopperBlockEntity) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/HugeMushroomBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/HugeMushroomBlock.java.patch index d1fc0c3f4486..6e29a5cde996 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/HugeMushroomBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/HugeMushroomBlock.java.patch @@ -3,23 +3,23 @@ @@ -45,6 +_,7 @@ @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { + public BlockState getStateForPlacement(final BlockPlaceContext context) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates BlockGetter level = context.getLevel(); - BlockPos clickedPos = context.getClickedPos(); + BlockPos pos = context.getClickedPos(); return this.defaultBlockState() @@ -67,6 +_,7 @@ - BlockState neighborState, - RandomSource random + final BlockState neighbourState, + final RandomSource random ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates - return neighborState.is(this) - ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), false) - : super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); + return neighbourState.is(this) + ? state.setValue(PROPERTY_BY_DIRECTION.get(directionToNeighbour), false) + : super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); @@ -74,6 +_,7 @@ @Override - protected BlockState rotate(BlockState state, Rotation rotation) { + protected BlockState rotate(final BlockState state, final Rotation rotation) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates return state.setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH)) .setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH)) @@ -27,7 +27,7 @@ @@ -84,6 +_,7 @@ @Override - protected BlockState mirror(BlockState state, Mirror mirror) { + protected BlockState mirror(final BlockState state, final Mirror mirror) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates return state.setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH)) .setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH)) diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/IceBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/IceBlock.java.patch index 8f529c109ad5..0d2f02e520a5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/IceBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/IceBlock.java.patch @@ -1,25 +1,25 @@ --- a/net/minecraft/world/level/block/IceBlock.java +++ b/net/minecraft/world/level/block/IceBlock.java -@@ -33,8 +_,13 @@ - } - - @Override -- public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) { -- super.playerDestroy(level, player, pos, state, blockEntity, stack); -+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion +@@ -40,8 +_,14 @@ + final BlockState state, + final @Nullable BlockEntity blockEntity, + final ItemStack destroyedWith ++ , boolean includeDrops, boolean dropExp // Paper - fix drops not preventing stats/food exhaustion + ) { +- super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith); ++ super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion + // Paper start - Improve Block#breakNaturally API -+ this.afterDestroy(level, pos, stack); ++ this.afterDestroy(level, pos, destroyedWith); + } -+ public void afterDestroy(Level level, BlockPos pos, ItemStack stack) { ++ public void afterDestroy(Level level, BlockPos pos, ItemStack destroyedWith) { + // Paper end - Improve Block#breakNaturally API - if (!EnchantmentHelper.hasTag(stack, EnchantmentTags.PREVENTS_ICE_MELTING)) { + if (!EnchantmentHelper.hasTag(destroyedWith, EnchantmentTags.PREVENTS_ICE_MELTING)) { if (level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos)) { level.removeBlock(pos, false); -@@ -56,7 +_,13 @@ +@@ -63,7 +_,13 @@ } - protected void melt(BlockState state, Level level, BlockPos pos) { + protected void melt(final BlockState state, final Level level, final BlockPos pos) { - if (level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos)) { + // Paper start - call BlockFadeEvent + final boolean waterEvaporates = level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LavaCauldronBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LavaCauldronBlock.java.patch index 2423a53edb45..6cc7719d2c16 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LavaCauldronBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LavaCauldronBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/LavaCauldronBlock.java +++ b/net/minecraft/world/level/block/LavaCauldronBlock.java -@@ -45,9 +_,11 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -52,9 +_,11 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + BlockPos savedPos = pos.immutable(); // Paper - track lava contact effectApplier.apply(InsideBlockEffectType.CLEAR_FREEZE); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LayeredCauldronBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LayeredCauldronBlock.java.patch index c1201af2871d..cd461c790af4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LayeredCauldronBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LayeredCauldronBlock.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/block/LayeredCauldronBlock.java +++ b/net/minecraft/world/level/block/LayeredCauldronBlock.java -@@ -80,39 +_,71 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -90,39 +_,71 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (level instanceof ServerLevel serverLevel) { BlockPos blockPos = pos.immutable(); - effectApplier.runBefore(InsideBlockEffectType.EXTINGUISH, entity1 -> { -- if (entity1.isOnFire() && entity1.mayInteract(serverLevel, blockPos)) { + effectApplier.runBefore(InsideBlockEffectType.EXTINGUISH, e -> { +- if (e.isOnFire() && e.mayInteract(serverLevel, blockPos)) { - this.handleEntityOnFireInside(state, level, blockPos); -+ if (entity1.isOnFire() && (entity instanceof net.minecraft.world.entity.player.Player || serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING)) && entity1.mayInteract(serverLevel, blockPos)) { // Paper - Fixes MC-248588 ++ if (e.isOnFire() && (entity instanceof net.minecraft.world.entity.player.Player || serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING)) && e.mayInteract(serverLevel, blockPos)) { // Paper - Fixes MC-248588 + // Paper start - cauldron level change event -+ if (this.handleEntityOnFireInside(state, level, blockPos, entity1)) { // Paper - track entity -+ InsideBlockEffectType.EXTINGUISH.effect().affect(entity1, blockPos); // apply extinguishing if event was not cancelled. ++ if (this.handleEntityOnFireInside(state, level, blockPos, e)) { // Paper - track entity ++ InsideBlockEffectType.EXTINGUISH.effect().affect(e, blockPos); // apply extinguishing if event was not cancelled. + } + // Paper end - cauldron level change event } @@ -24,9 +24,9 @@ + // effectApplier.apply(InsideBlockEffectType.EXTINGUISH); // Paper - manually applied above - cauldron level change event - delay to not extinguish when event is cancelled } -- private void handleEntityOnFireInside(BlockState state, Level level, BlockPos pos) { +- private void handleEntityOnFireInside(final BlockState state, final Level level, final BlockPos pos) { + // CraftBukkit start -+ private boolean handleEntityOnFireInside(BlockState state, Level level, BlockPos pos, @javax.annotation.Nullable Entity entity) { ++ private boolean handleEntityOnFireInside(final BlockState state, final Level level, final BlockPos pos, @org.jspecify.annotations.Nullable Entity entity) { if (this.precipitationType == Biome.Precipitation.SNOW) { - lowerFillLevel(Blocks.WATER_CAULDRON.defaultBlockState().setValue(LEVEL, state.getValue(LEVEL)), level, pos); + return lowerFillLevel(Blocks.WATER_CAULDRON.defaultBlockState().setValue(LEVEL, state.getValue(LEVEL)), level, pos, entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.EXTINGUISH); // CraftBukkit @@ -36,29 +36,29 @@ } } - public static void lowerFillLevel(BlockState state, Level level, BlockPos pos) { + public static void lowerFillLevel(final BlockState state, final Level level, final BlockPos pos) { + // Paper start + lowerFillLevel(state, level, pos, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.UNKNOWN); + } -+ public static boolean lowerFillLevel(BlockState state, Level level, BlockPos pos, @javax.annotation.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason) { ++ public static boolean lowerFillLevel(BlockState state, Level level, BlockPos pos, @org.jspecify.annotations.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason) { + // Paper end - int i = state.getValue(LEVEL) - 1; - BlockState blockState = i == 0 ? Blocks.CAULDRON.defaultBlockState() : state.setValue(LEVEL, i); -- level.setBlockAndUpdate(pos, blockState); -- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + int newLevel = state.getValue(LEVEL) - 1; + BlockState newState = newLevel == 0 ? Blocks.CAULDRON.defaultBlockState() : state.setValue(LEVEL, newLevel); +- level.setBlockAndUpdate(pos, newState); +- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); - } -+ return changeLevel(level, pos, blockState, entity, reason); // Paper ++ return changeLevel(level, pos, newState, entity, reason); // Paper + } + // CraftBukkit start + // Paper start - Call CauldronLevelChangeEvent -+ public static boolean changeLevel(Level level, BlockPos pos, BlockState newBlock, @javax.annotation.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable ++ public static boolean changeLevel(Level level, BlockPos pos, BlockState newBlock, @org.jspecify.annotations.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable + return changeLevel(level, pos, newBlock, entity, reason, true); + } + -+ public static boolean changeLevel(Level level, BlockPos pos, BlockState newBlock, @javax.annotation.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable ++ public static boolean changeLevel(Level level, BlockPos pos, BlockState newBlock, @org.jspecify.annotations.Nullable Entity entity, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable + // Paper end - Call CauldronLevelChangeEvent + org.bukkit.craftbukkit.block.CraftBlockState newState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos); -+ newState.setData(newBlock); ++ newState.setBlock(newBlock); + + org.bukkit.event.block.CauldronLevelChangeEvent event = new org.bukkit.event.block.CauldronLevelChangeEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), @@ -74,23 +74,23 @@ + // CraftBukkit end @Override - public void handlePrecipitation(BlockState state, Level level, BlockPos pos, Biome.Precipitation precipitation) { + public void handlePrecipitation(final BlockState state, final Level level, final BlockPos pos, final Biome.Precipitation precipitation) { if (CauldronBlock.shouldHandlePrecipitation(level, precipitation) && state.getValue(LEVEL) != 3 && precipitation == this.precipitationType) { - BlockState blockState = state.cycle(LEVEL); -- level.setBlockAndUpdate(pos, blockState); -- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); -+ changeLevel(level, pos, blockState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit + BlockState newState = state.cycle(LEVEL); +- level.setBlockAndUpdate(pos, newState); +- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); ++ changeLevel(level, pos, newState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit } } -@@ -130,8 +_,11 @@ - protected void receiveStalactiteDrip(BlockState state, Level level, BlockPos pos, Fluid fluid) { +@@ -140,8 +_,11 @@ + protected void receiveStalactiteDrip(final BlockState state, final Level level, final BlockPos pos, final Fluid fluid) { if (!this.isFull(state)) { - BlockState blockState = state.setValue(LEVEL, state.getValue(LEVEL) + 1); -- level.setBlockAndUpdate(pos, blockState); -- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + BlockState newState = state.setValue(LEVEL, state.getValue(LEVEL) + 1); +- level.setBlockAndUpdate(pos, newState); +- level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); + // CraftBukkit start -+ if (!changeLevel(level, pos, blockState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { ++ if (!changeLevel(level, pos, newState, null, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { + return; + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch index 8cb50108abfb..0fa6ea60b1e9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LeavesBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/LeavesBlock.java @@ -66,6 +_,14 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (this.decaying(state)) { + // CraftBukkit start + org.bukkit.event.block.LeavesDecayEvent event = new org.bukkit.event.block.LeavesDecayEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch index e8377204ce2a..533c233c5525 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch @@ -1,37 +1,37 @@ --- a/net/minecraft/world/level/block/LecternBlock.java +++ b/net/minecraft/world/level/block/LecternBlock.java -@@ -137,7 +_,24 @@ - - private static void placeBook(@Nullable LivingEntity entity, Level level, BlockPos pos, BlockState state, ItemStack stack) { - if (level.getBlockEntity(pos) instanceof LecternBlockEntity lecternBlockEntity) { -- lecternBlockEntity.setBook(stack.consumeAndReturn(1, entity)); +@@ -141,7 +_,24 @@ + final @Nullable LivingEntity sourceEntity, final Level level, final BlockPos pos, final BlockState state, final ItemStack book + ) { + if (level.getBlockEntity(pos) instanceof LecternBlockEntity lectern) { +- lectern.setBook(book.consumeAndReturn(1, sourceEntity)); + // Paper start - Add PlayerInsertLecternBookEvent + ItemStack eventSourcedBookStack = null; -+ if (entity instanceof final net.minecraft.server.level.ServerPlayer serverPlayer) { ++ if (sourceEntity instanceof final net.minecraft.server.level.ServerPlayer serverPlayer) { + final io.papermc.paper.event.player.PlayerInsertLecternBookEvent event = new io.papermc.paper.event.player.PlayerInsertLecternBookEvent( + serverPlayer.getBukkitEntity(), + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), -+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack.copyWithCount(1)) ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(book.copyWithCount(1)) + ); + if (!event.callEvent()) return; + eventSourcedBookStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getBook()); + } + if (eventSourcedBookStack == null) { -+ eventSourcedBookStack = stack.consumeAndReturn(1, entity); ++ eventSourcedBookStack = book.consumeAndReturn(1, sourceEntity); + } else { -+ stack.consume(1, entity); ++ book.consume(1, sourceEntity); + } -+ lecternBlockEntity.setBook(eventSourcedBookStack); ++ lectern.setBook(eventSourcedBookStack); + // Paper end - Add PlayerInsertLecternBookEvent - resetBookState(entity, level, pos, state, true); + resetBookState(sourceEntity, level, pos, state, true); level.playSound(null, pos, SoundEvents.BOOK_PUT, SoundSource.BLOCKS, 1.0F, 1.0F); } -@@ -157,6 +_,16 @@ +@@ -161,6 +_,16 @@ } - private static void changePowered(Level level, BlockPos pos, BlockState state, boolean powered) { + private static void changePowered(final Level level, final BlockPos pos, final BlockState state, final boolean isPowered) { + // Paper start - Call BlockRedstoneEvent properly -+ final int currentRedstoneLevel = state.getValue(LecternBlock.POWERED) ? 15 : 0, targetRedstoneLevel = powered ? 15 : 0; ++ final int currentRedstoneLevel = state.getValue(LecternBlock.POWERED) ? 15 : 0, targetRedstoneLevel = isPowered ? 15 : 0; + if (currentRedstoneLevel != targetRedstoneLevel) { + final org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, currentRedstoneLevel, targetRedstoneLevel); + @@ -40,12 +40,12 @@ + } + } + // Paper end - Call BlockRedstoneEvent properly - level.setBlock(pos, state.setValue(POWERED, powered), Block.UPDATE_ALL); + level.setBlock(pos, state.setValue(POWERED, isPowered), Block.UPDATE_ALL); updateBelow(level, pos, state); } -@@ -243,8 +_,7 @@ +@@ -257,8 +_,7 @@ - private void openScreen(Level level, BlockPos pos, Player player) { + private void openScreen(final Level level, final BlockPos pos, final Player player) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof LecternBlockEntity) { - player.openMenu((LecternBlockEntity)blockEntity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LeverBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LeverBlock.java.patch index 9777099fd666..8950dfb135b6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LeverBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LeverBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/LeverBlock.java +++ b/net/minecraft/world/level/block/LeverBlock.java -@@ -67,6 +_,19 @@ - makeParticle(blockState, level, pos, 1.0F); +@@ -69,6 +_,19 @@ + makeParticle(stateAfter, level, pos, 1.0F); } } else { + // CraftBukkit start - Interact Lever -+ boolean powered = state.getValue(LeverBlock.POWERED); // Old powered state ++ boolean powered = stateBefore.getValue(LeverBlock.POWERED); // Old powered state + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + int old = (powered) ? 15 : 0; + int current = (!powered) ? 15 : 0; @@ -17,6 +17,6 @@ + return InteractionResult.SUCCESS; + } + // CraftBukkit end - this.pull(state, level, pos, null); + this.pull(stateBefore, level, pos, null); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LightBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LightBlock.java.patch index 8b3d19d59cd9..27f579545177 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LightBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LightBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/LightBlock.java +++ b/net/minecraft/world/level/block/LightBlock.java @@ -49,6 +_,13 @@ - protected void createBlockStateDefinition(StateDefinition.Builder builder) { + protected void createBlockStateDefinition(final StateDefinition.Builder builder) { builder.add(LEVEL, WATERLOGGED); } + // Paper start - prevent unintended light block manipulation @@ -13,4 +13,4 @@ + // Paper end - prevent unintended light block manipulation @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + protected InteractionResult useWithoutItem( diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LightningRodBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LightningRodBlock.java.patch index 9d7c7a1f2797..68822dac843b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LightningRodBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LightningRodBlock.java.patch @@ -3,7 +3,7 @@ @@ -82,6 +_,18 @@ } - public void onLightningStrike(BlockState state, Level level, BlockPos pos) { + public void onLightningStrike(final BlockState state, final Level level, final BlockPos pos) { + // CraftBukkit start + boolean powered = state.getValue(LightningRodBlock.POWERED); + int old = (powered) ? 15 : 0; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WaterlilyBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LilyPadBlock.java.patch similarity index 69% rename from paper-server/patches/sources/net/minecraft/world/level/block/WaterlilyBlock.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/LilyPadBlock.java.patch index ae0899c7f52c..9d56a2eedc9f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WaterlilyBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LilyPadBlock.java.patch @@ -1,11 +1,11 @@ ---- a/net/minecraft/world/level/block/WaterlilyBlock.java -+++ b/net/minecraft/world/level/block/WaterlilyBlock.java -@@ -30,8 +_,14 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +--- a/net/minecraft/world/level/block/LilyPadBlock.java ++++ b/net/minecraft/world/level/block/LilyPadBlock.java +@@ -39,8 +_,14 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - super.entityInside(state, level, pos, entity, effectApplier, pastEdges); + super.entityInside(state, level, pos, entity, effectApplier, isPrecise); if (level instanceof ServerLevel && entity instanceof AbstractBoat) { + // CraftBukkit start + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch index fc1018d1f279..178213bccbb7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch @@ -1,16 +1,18 @@ --- a/net/minecraft/world/level/block/LiquidBlock.java +++ b/net/minecraft/world/level/block/LiquidBlock.java -@@ -139,9 +_,30 @@ +@@ -150,7 +_,7 @@ @Override - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { if (this.shouldSpreadLiquid(level, pos, state)) { - level.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(level)); -- } -- } + level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava -+ } -+ } -+ + } + + if (shouldBubbleColumnOccupy(state)) { +@@ -167,6 +_,27 @@ + } + } + + // Paper start - Configurable speed for water flowing over lava + public int getFlowSpeed(Level level, BlockPos pos) { + if (net.minecraft.core.registries.BuiltInRegistries.FLUID.wrapAsHolder(this.fluid).is(FluidTags.WATER)) { @@ -31,33 +33,34 @@ + return fluidState != null && fluidState.is(FluidTags.LAVA); + } + // Paper end - Configurable speed for water flowing over lava - ++ @Override protected BlockState updateShape( -@@ -164,7 +_,7 @@ - @Override - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + final BlockState state, +@@ -198,7 +_,7 @@ + final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston + ) { if (this.shouldSpreadLiquid(level, pos, state)) { - level.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(level)); + level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava } - } -@@ -176,14 +_,20 @@ - BlockPos blockPos = pos.relative(direction.getOpposite()); - if (level.getFluidState(blockPos).is(FluidTags.WATER)) { - Block block = level.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; -- level.setBlockAndUpdate(pos, block.defaultBlockState()); + if (shouldBubbleColumnOccupy(state)) { +@@ -221,14 +_,20 @@ + BlockPos neighbourPos = pos.relative(direction.getOpposite()); + if (level.getFluidState(neighbourPos).is(FluidTags.WATER)) { + Block convertToBlock = level.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; +- level.setBlockAndUpdate(pos, convertToBlock.defaultBlockState()); - this.fizz(level, pos); + // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, block.defaultBlockState(), Block.UPDATE_ALL)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, convertToBlock.defaultBlockState(), Block.UPDATE_ALL)) { + this.fizz(level, pos); + } + // CraftBukkit end return false; } - if (isSoulSoil && level.getBlockState(blockPos).is(Blocks.BLUE_ICE)) { + if (isOverSoulSoil && level.getBlockState(neighbourPos).is(Blocks.BLUE_ICE)) { - level.setBlockAndUpdate(pos, Blocks.BASALT.defaultBlockState()); - this.fizz(level, pos); + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LoomBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LoomBlock.java.patch index 99f5f7cec14c..dba6733fe91d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LoomBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LoomBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/LoomBlock.java +++ b/net/minecraft/world/level/block/LoomBlock.java -@@ -32,8 +_,7 @@ - - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -34,8 +_,7 @@ + protected InteractionResult useWithoutItem( + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { - if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (!level.isClientSide() && player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch index a3fec4f2d3b9..ba551b0baf80 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/MagmaBlock.java +++ b/net/minecraft/world/level/block/MagmaBlock.java -@@ -29,7 +_,7 @@ +@@ -23,7 +_,7 @@ @Override - public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { + public void stepOn(final Level level, final BlockPos pos, final BlockState onState, final Entity entity) { if (!entity.isSteppingCarefully() && entity instanceof LivingEntity) { - entity.hurt(level.damageSources().hotFloor(), 1.0F); + entity.hurt(level.damageSources().hotFloor().eventBlockDamager(level, pos), 1.0F); // CraftBukkit } - super.stepOn(level, pos, state, entity); + super.stepOn(level, pos, onState, entity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MangrovePropaguleBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MangrovePropaguleBlock.java.patch index 713e011d6d6c..1cf4d03ee288 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MangrovePropaguleBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MangrovePropaguleBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/MangrovePropaguleBlock.java @@ -102,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!isHanging(state)) { - if (random.nextInt(7) == 0) { + if (random.nextFloat() < (level.spigotConfig.saplingModifier / (100.0F * 7))) { // Paper - Fix Spigot growth modifiers diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch index 0418f7e49fee..cb37ea773907 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/MultifaceSpreader.java +++ b/net/minecraft/world/level/block/MultifaceSpreader.java -@@ -152,14 +_,14 @@ - level.getChunk(pos.pos()).markPosForPostprocessing(pos.pos()); +@@ -176,14 +_,14 @@ + level.getChunk(spreadPos.pos()).markPosForPostprocessing(spreadPos.pos()); } -- return level.setBlock(pos.pos(), stateForPlacement, Block.UPDATE_CLIENTS); -+ return org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos.source(), pos.pos(), stateForPlacement, Block.UPDATE_CLIENTS, true); // CraftBukkit +- return level.setBlock(spreadPos.pos(), spreadState, Block.UPDATE_CLIENTS); ++ return org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, spreadPos.source(), spreadPos.pos(), spreadState, Block.UPDATE_CLIENTS, true); // CraftBukkit } else { return false; } @@ -17,26 +17,26 @@ } @FunctionalInterface -@@ -171,19 +_,19 @@ +@@ -195,19 +_,19 @@ SAME_POSITION { @Override - public MultifaceSpreader.SpreadPos getSpreadPos(BlockPos pos, Direction face, Direction spreadDirection) { -- return new MultifaceSpreader.SpreadPos(pos, face); -+ return new MultifaceSpreader.SpreadPos(pos, face, pos); // CraftBukkit + public MultifaceSpreader.SpreadPos getSpreadPos(final BlockPos pos, final Direction spreadDirection, final Direction fromFace) { +- return new MultifaceSpreader.SpreadPos(pos, spreadDirection); ++ return new MultifaceSpreader.SpreadPos(pos, spreadDirection, pos); // CraftBukkit } }, SAME_PLANE { @Override - public MultifaceSpreader.SpreadPos getSpreadPos(BlockPos pos, Direction face, Direction spreadDirection) { -- return new MultifaceSpreader.SpreadPos(pos.relative(face), spreadDirection); -+ return new MultifaceSpreader.SpreadPos(pos.relative(face), spreadDirection, pos); // CraftBukkit + public MultifaceSpreader.SpreadPos getSpreadPos(final BlockPos pos, final Direction spreadDirection, final Direction fromFace) { +- return new MultifaceSpreader.SpreadPos(pos.relative(spreadDirection), fromFace); ++ return new MultifaceSpreader.SpreadPos(pos.relative(spreadDirection), fromFace, pos); // CraftBukkit } }, WRAP_AROUND { @Override - public MultifaceSpreader.SpreadPos getSpreadPos(BlockPos pos, Direction face, Direction spreadDirection) { -- return new MultifaceSpreader.SpreadPos(pos.relative(face).relative(spreadDirection), face.getOpposite()); -+ return new MultifaceSpreader.SpreadPos(pos.relative(face).relative(spreadDirection), face.getOpposite(), pos); // CraftBukkit + public MultifaceSpreader.SpreadPos getSpreadPos(final BlockPos pos, final Direction spreadDirection, final Direction fromFace) { +- return new MultifaceSpreader.SpreadPos(pos.relative(spreadDirection).relative(fromFace), spreadDirection.getOpposite()); ++ return new MultifaceSpreader.SpreadPos(pos.relative(spreadDirection).relative(fromFace), spreadDirection.getOpposite(), pos); // CraftBukkit } }; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch index 5cd752321a23..d04287fd33da 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch @@ -3,26 +3,26 @@ @@ -46,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, BlockPos pos, final RandomSource random) { - if (random.nextInt(25) == 0) { + if (random.nextFloat() < (level.spigotConfig.mushroomModifier / (100.0F * 25))) { // Spigot - SPIGOT-7159: Better modifier resolution - int i = 5; - int i1 = 4; + int max = 5; + int r = 4; @@ -59,6 +_,7 @@ } - BlockPos blockPos1 = pos.offset(random.nextInt(3) - 1, random.nextInt(2) - random.nextInt(2), random.nextInt(3) - 1); + BlockPos offset = pos.offset(random.nextInt(3) - 1, random.nextInt(2) - random.nextInt(2), random.nextInt(3) - 1); + final BlockPos sourcePos = pos; // Paper - Use correct source for mushroom block spread event - for (int i2 = 0; i2 < 4; i2++) { - if (level.isEmptyBlock(blockPos1) && state.canSurvive(level, blockPos1)) { + for (int i = 0; i < 4; i++) { + if (level.isEmptyBlock(offset) && state.canSurvive(level, offset)) { @@ -69,7 +_,7 @@ } - if (level.isEmptyBlock(blockPos1) && state.canSurvive(level, blockPos1)) { -- level.setBlock(blockPos1, state, Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, sourcePos, blockPos1, state, Block.UPDATE_CLIENTS); // CraftBukkit // Paper - Use correct source for mushroom block spread event + if (level.isEmptyBlock(offset) && state.canSurvive(level, offset)) { +- level.setBlock(offset, state, Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, sourcePos, offset, state, Block.UPDATE_CLIENTS); // CraftBukkit // Paper - Use correct source for mushroom block spread event } } } @@ -31,6 +31,6 @@ } else { level.removeBlock(pos, false); + SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit - if (optional.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) { + if (feature.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) { return true; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NetherFungusBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NetherFungusBlock.java.patch new file mode 100644 index 000000000000..2b50d69daf24 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NetherFungusBlock.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/level/block/NetherFungusBlock.java ++++ b/net/minecraft/world/level/block/NetherFungusBlock.java +@@ -80,6 +_,17 @@ + + @Override + public void performBonemeal(final ServerLevel level, final RandomSource random, final BlockPos pos, final BlockState state) { +- this.getFeature(level).ifPresent(feature -> feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)); ++ this.getFeature(level) ++ // CraftBukkit start ++ .map((value) -> { ++ if (this == Blocks.WARPED_FUNGUS) { ++ SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS; ++ } else if (this == Blocks.CRIMSON_FUNGUS) { ++ SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS; ++ } ++ return value; ++ }) ++ .ifPresent(feature -> feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)); ++ // CraftBukkit end + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch index 30b239c9d2f8..18b9b33953c2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch @@ -3,7 +3,7 @@ @@ -66,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, BlockPos pos, final RandomSource random) { - if (level.isSpawningMonsters() + if (level.spigotConfig.enableZombiePigmenPortalSpawns && level.isSpawningMonsters() // Spigot && level.environmentAttributes().getValue(EnvironmentAttributes.NETHER_PORTAL_SPAWNS_PIGLINS, pos) @@ -24,10 +24,10 @@ Entity vehicle = entity.getVehicle(); if (vehicle != null) { vehicle.setPortalCooldown(); -@@ -108,7 +_,13 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -115,7 +_,13 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false)) { + // CraftBukkit start - Entity in portal @@ -38,76 +38,77 @@ entity.setAsInsidePortal(this, pos); } } -@@ -126,23 +_,47 @@ +@@ -133,16 +_,39 @@ @Override - public @Nullable TeleportTransition getPortalDestination(ServerLevel level, Entity entity, BlockPos pos) { -- ResourceKey resourceKey = level.dimension() == Level.NETHER ? Level.OVERWORLD : Level.NETHER; -+ // CraftBukkit start -+ ResourceKey resourceKey = level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER ? Level.OVERWORLD : Level.NETHER; - ServerLevel level1 = level.getServer().getLevel(resourceKey); + public @Nullable TeleportTransition getPortalDestination(final ServerLevel currentLevel, final Entity entity, final BlockPos portalEntryPos) { +- ResourceKey newDimension = currentLevel.dimension() == Level.NETHER ? Level.OVERWORLD : Level.NETHER; ++ ResourceKey newDimension = currentLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER ? Level.OVERWORLD : Level.NETHER; // CraftBukkit + ServerLevel newLevel = currentLevel.getServer().getLevel(newDimension); + // Paper start - Add EntityPortalReadyEvent -+ io.papermc.paper.event.entity.EntityPortalReadyEvent portalReadyEvent = new io.papermc.paper.event.entity.EntityPortalReadyEvent(entity.getBukkitEntity(), level1 == null ? null : level1.getWorld(), org.bukkit.PortalType.NETHER); ++ io.papermc.paper.event.entity.EntityPortalReadyEvent portalReadyEvent = new io.papermc.paper.event.entity.EntityPortalReadyEvent(entity.getBukkitEntity(), newLevel == null ? null : newLevel.getWorld(), org.bukkit.PortalType.NETHER); + if (!portalReadyEvent.callEvent()) { + entity.portalProcess = null; + return null; + } -+ level1 = portalReadyEvent.getTargetWorld() == null ? null : ((org.bukkit.craftbukkit.CraftWorld) portalReadyEvent.getTargetWorld()).getHandle(); ++ newLevel = portalReadyEvent.getTargetWorld() == null ? null : ((org.bukkit.craftbukkit.CraftWorld) portalReadyEvent.getTargetWorld()).getHandle(); + // Paper end - Add EntityPortalReadyEvent - if (level1 == null) { + if (newLevel == null) { return null; } else { -- boolean flag = level1.dimension() == Level.NETHER; -+ boolean flag = level1.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER; // CraftBukkit - WorldBorder worldBorder = level1.getWorldBorder(); - double teleportationScale = DimensionType.getTeleportationScale(level.dimensionType(), level1.dimensionType()); - BlockPos blockPos = worldBorder.clampToBounds(entity.getX() * teleportationScale, entity.getY(), entity.getZ() * teleportationScale); -- return this.getExitPortal(level1, entity, pos, blockPos, flag, worldBorder); +- boolean toNether = newLevel.dimension() == Level.NETHER; ++ boolean toNether = newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER; // CraftBukkit + WorldBorder newWorldBorder = newLevel.getWorldBorder(); + double teleportationScale = DimensionType.getTeleportationScale(currentLevel.dimensionType(), newLevel.dimensionType()); + BlockPos approximateExitPos = newWorldBorder.clampToBounds(entity.getX() * teleportationScale, entity.getY(), entity.getZ() * teleportationScale); +- return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder); + // Paper start - Configurable portal search radius -+ int portalSearchRadius = level1.paperConfig().environment.portalSearchRadius; -+ if (entity.level().paperConfig().environment.portalSearchVanillaDimensionScaling && flag) { // flag = is going to nether -+ portalSearchRadius = (int) (portalSearchRadius / level1.dimensionType().coordinateScale()); ++ int portalSearchRadius = newLevel.paperConfig().environment.portalSearchRadius; ++ if (entity.level().paperConfig().environment.portalSearchVanillaDimensionScaling && toNether) { ++ portalSearchRadius = (int) (portalSearchRadius / newLevel.dimensionType().coordinateScale()); + } + // Paper end - Configurable portal search radius + // CraftBukkit start -+ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level1), org.bukkit.PortalType.NETHER, portalSearchRadius, level1.paperConfig().environment.portalCreateRadius); // Paper - use custom portal search radius ++ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(approximateExitPos, newLevel), org.bukkit.PortalType.NETHER, portalSearchRadius, newLevel.paperConfig().environment.portalCreateRadius); // Paper - use custom portal search radius + if (result == null) { + return null; + } -+ level1 = ((org.bukkit.craftbukkit.CraftWorld) result.to().getWorld()).getHandle(); -+ worldBorder = level1.getWorldBorder(); -+ blockPos = worldBorder.clampToBounds(result.to().getX(), result.to().getY(), result.to().getZ()); -+ return this.getExitPortal(level1, entity, pos, blockPos, worldBorder, result); ++ newLevel = ((org.bukkit.craftbukkit.CraftWorld) result.to().getWorld()).getHandle(); ++ newWorldBorder = newLevel.getWorldBorder(); ++ approximateExitPos = newWorldBorder.clampToBounds(result.to().getX(), result.to().getY(), result.to().getZ()); ++ return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder, result); + // CraftBukkit end } } - private @Nullable TeleportTransition getExitPortal( -- ServerLevel level, Entity entity, BlockPos pos, BlockPos exitPos, boolean isNether, WorldBorder worldBorder -+ ServerLevel level, Entity entity, BlockPos pos, BlockPos exitPos, WorldBorder worldBorder, org.bukkit.craftbukkit.event.PortalEventResult result // CraftBukkit +@@ -153,8 +_,9 @@ + final BlockPos approximateExitPos, + final boolean toNether, + final WorldBorder worldBorder ++ , org.bukkit.craftbukkit.event.PortalEventResult result // CraftBukkit ) { -- Optional optional = level.getPortalForcer().findClosestPortalPosition(exitPos, isNether, worldBorder); -+ Optional optional = level.getPortalForcer().findClosestPortalPosition(exitPos, worldBorder, result.searchRadius()); // CraftBukkit - BlockUtil.FoundRectangle largestRectangleAround; - TeleportTransition.PostTeleportTransition postTeleportTransition; - if (optional.isPresent()) { -@@ -157,17 +_,22 @@ - blockPos1 -> level.getBlockState(blockPos1) == blockState +- Optional exitPortalPos = newLevel.getPortalForcer().findClosestPortalPosition(approximateExitPos, toNether, worldBorder); ++ Optional exitPortalPos = newLevel.getPortalForcer().findClosestPortalPosition(approximateExitPos, worldBorder, result.searchRadius()); // CraftBukkit + BlockUtil.FoundRectangle exitPortal; + TeleportTransition.PostTeleportTransition post; + if (exitPortalPos.isPresent()) { +@@ -169,17 +_,22 @@ + blockPos -> newLevel.getBlockState(blockPos) == portalState ); - postTeleportTransition = TeleportTransition.PLAY_PORTAL_SOUND.then(entity1 -> entity1.placePortalTicket(blockPos)); + post = TeleportTransition.PLAY_PORTAL_SOUND.then(e -> e.placePortalTicket(pos)); - } else { + } else if (result.canCreatePortal()) { // CraftBukkit - Direction.Axis axis = entity.level().getBlockState(pos).getOptionalValue(AXIS).orElse(Direction.Axis.X); -- Optional optional1 = level.getPortalForcer().createPortal(exitPos, axis); -+ Optional optional1 = level.getPortalForcer().createPortal(exitPos, axis, entity, result.createRadius()); // CraftBukkit - if (optional1.isEmpty()) { + Direction.Axis sourcePortalAxis = entity.level().getBlockState(portalEntryPos).getOptionalValue(AXIS).orElse(Direction.Axis.X); +- Optional createdExit = newLevel.getPortalForcer().createPortal(approximateExitPos, sourcePortalAxis); ++ Optional createdExit = newLevel.getPortalForcer().createPortal(approximateExitPos, sourcePortalAxis, entity, result.createRadius()); // CraftBukkit + if (createdExit.isEmpty()) { - LOGGER.error("Unable to create a portal, likely target out of worldborder"); + // LOGGER.error("Unable to create a portal, likely target out of worldborder"); // CraftBukkit return null; } - largestRectangleAround = optional1.get(); - postTeleportTransition = TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET); + exitPortal = createdExit.get(); + post = TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET); } + // CraftBukkit start + else { @@ -115,14 +116,14 @@ + } + // CraftBukkit end - return getDimensionTransitionFromExit(entity, pos, largestRectangleAround, level, postTeleportTransition); + return getDimensionTransitionFromExit(entity, portalEntryPos, exitPortal, newLevel, post); } -@@ -213,7 +_,7 @@ - boolean flag = axis1 == Direction.Axis.X; - Vec3 vec3 = new Vec3(blockPos.getX() + (flag ? d2 : d4), blockPos.getY() + d3, blockPos.getZ() + (flag ? d4 : d2)); - Vec3 vec31 = PortalShape.findCollisionFreePosition(vec3, level, entity, dimensions); -- return new TeleportTransition(level, vec31, Vec3.ZERO, i, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition); -+ return new TeleportTransition(level, vec31, Vec3.ZERO, i, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // CraftBukkit +@@ -234,7 +_,7 @@ + ); + Vec3 collisionFreePos = PortalShape.findCollisionFreePosition(targetPos, newLevel, entity, dimensions); + return new TeleportTransition( +- newLevel, collisionFreePos, Vec3.ZERO, outputRotation, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition ++ newLevel, collisionFreePos, Vec3.ZERO, outputRotation, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL // CraftBukkit + ); } - @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch index a36c5dc3bd90..10a6456a1e6d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/NetherWartBlock.java +++ b/net/minecraft/world/level/block/NetherWartBlock.java -@@ -50,9 +_,9 @@ +@@ -51,9 +_,9 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - int ageValue = state.getValue(AGE); -- if (ageValue < 3 && random.nextInt(10) == 0) { -+ if (ageValue < 3 && random.nextFloat() < (level.spigotConfig.wartModifier / (100.0F * 10))) { // Spigot - SPIGOT-7159: Better modifier resolution - state = state.setValue(AGE, ageValue + 1); + protected void randomTick(BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + int age = state.getValue(AGE); +- if (age < 3 && random.nextInt(10) == 0) { ++ if (age < 3 && random.nextFloat() < (level.spigotConfig.wartModifier / (100.0F * 10))) { // Spigot - SPIGOT-7159: Better modifier resolution + state = state.setValue(AGE, age + 1); - level.setBlock(pos, state, Block.UPDATE_CLIENTS); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state, Block.UPDATE_CLIENTS); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch index db0d3e70e01e..d2f16d4877f8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch @@ -3,62 +3,65 @@ @@ -64,6 +_,7 @@ @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { + public BlockState getStateForPlacement(final BlockPlaceContext context) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return this.defaultBlockState(); // Paper - place without considering instrument return this.setInstrument(context.getLevel(), context.getClickedPos(), this.defaultBlockState()); } @@ -78,6 +_,7 @@ - BlockState neighborState, - RandomSource random + final BlockState neighbourState, + final RandomSource random ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return state; // Paper - prevent noteblock instrument from updating - boolean flag = direction.getAxis() == Direction.Axis.Y; - return flag + boolean neighborDirectionSetsInstrument = directionToNeighbour.getAxis() == Direction.Axis.Y; + return neighborDirectionSetsInstrument ? this.setInstrument(level, pos, state) -@@ -86,10 +_,12 @@ +@@ -86,12 +_,14 @@ @Override - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + protected void neighborChanged( +- final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston ++ BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston // Paper - make state non-final + ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating - boolean hasNeighborSignal = level.hasNeighborSignal(pos); - if (hasNeighborSignal != state.getValue(POWERED)) { - if (hasNeighborSignal) { + boolean signal = level.hasNeighborSignal(pos); + if (signal != state.getValue(POWERED)) { + if (signal) { this.playNote(null, state, level, pos); + state = level.getBlockState(pos); // CraftBukkit - SPIGOT-5617: update in case changed in event } - level.setBlock(pos, state.setValue(POWERED, hasNeighborSignal), Block.UPDATE_ALL); -@@ -115,7 +_,7 @@ + level.setBlock(pos, state.setValue(POWERED, signal), Block.UPDATE_ALL); +@@ -123,7 +_,7 @@ @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + protected InteractionResult useWithoutItem(BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult) { if (!level.isClientSide()) { - state = state.cycle(NOTE); + if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) state = state.cycle(NoteBlock.NOTE); // Paper - prevent noteblock note from updating level.setBlock(pos, state, Block.UPDATE_ALL); this.playNote(player, state, level, pos); player.awardStat(Stats.TUNE_NOTEBLOCK); -@@ -139,9 +_,13 @@ +@@ -147,9 +_,13 @@ @Override - protected boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) { - NoteBlockInstrument noteBlockInstrument = state.getValue(INSTRUMENT); + protected boolean triggerEvent(final BlockState state, final Level level, final BlockPos pos, final int b0, final int b1) { + NoteBlockInstrument instrument = state.getValue(INSTRUMENT); + // Paper start - move NotePlayEvent call to fix instrument/note changes -+ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(level, pos, noteBlockInstrument, state.getValue(NOTE)); ++ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(level, pos, instrument, state.getValue(NOTE)); + if (event.isCancelled()) return false; + // Paper end - move NotePlayEvent call to fix instrument/note changes - float pitchFromNote; - if (noteBlockInstrument.isTunable()) { -- int noteValue = state.getValue(NOTE); -+ int noteValue = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes - pitchFromNote = getPitchFromNote(noteValue); - level.addParticle(ParticleTypes.NOTE, pos.getX() + 0.5, pos.getY() + 1.2, pos.getZ() + 0.5, noteValue / 24.0, 0.0, 0.0); + float pitch; + if (instrument.isTunable()) { +- int note = state.getValue(NOTE); ++ int note = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes + pitch = getPitchFromNote(note); + level.addParticle(ParticleTypes.NOTE, pos.getX() + 0.5, pos.getY() + 1.2, pos.getZ() + 0.5, note / 24.0, 0.0, 0.0); } else { -@@ -157,7 +_,7 @@ +@@ -165,7 +_,7 @@ - holder = Holder.direct(SoundEvent.createVariableRangeEvent(customSoundId)); + soundEvent = Holder.direct(SoundEvent.createVariableRangeEvent(soundId)); } else { -- holder = noteBlockInstrument.getSoundEvent(); -+ holder = org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes +- soundEvent = instrument.getSoundEvent(); ++ soundEvent = org.bukkit.craftbukkit.block.data.CraftBlockData.toVanilla(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes } level.playSeededSound( diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NyliumBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NyliumBlock.java.patch index c447936cca0c..bac62e06fc89 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NyliumBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NyliumBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/NyliumBlock.java @@ -39,6 +_,11 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (!canBeNylium(state, level, pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.NETHERRACK.defaultBlockState()).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch index 88732b7a4a91..dc1cb72447f4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/ObserverBlock.java @@ -50,8 +_,18 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (state.getValue(POWERED)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PitcherCropBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PitcherCropBlock.java.patch index f692f02e707a..e1f5016ae192 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PitcherCropBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PitcherCropBlock.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/level/block/PitcherCropBlock.java +++ b/net/minecraft/world/level/block/PitcherCropBlock.java -@@ -117,6 +_,7 @@ - - @Override - public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -125,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.getGameRules().get(GameRules.MOB_GRIEFING)) { serverLevel.destroyBlock(pos, true, entity); } -@@ -139,7 +_,7 @@ +@@ -147,7 +_,7 @@ @Override - public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + public void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { float growthSpeed = CropBlock.getGrowthSpeed(this, level, pos); -- boolean flag = random.nextInt((int)(25.0F / growthSpeed) + 1) == 0; -+ boolean flag = random.nextFloat() < (level.spigotConfig.pitcherPlantModifier / (100.0F * (Math.floor(25.0F / growthSpeed) + 1))); // Paper - Fix Spigot growth modifiers - if (flag) { +- boolean shouldProgressGrowth = random.nextInt((int)(25.0F / growthSpeed) + 1) == 0; ++ boolean shouldProgressGrowth = random.nextFloat() < (level.spigotConfig.pitcherPlantModifier / (100.0F * (Math.floor(25.0F / growthSpeed) + 1))); // Paper - Fix Spigot growth modifiers + if (shouldProgressGrowth) { this.grow(level, state, pos, 1); } -@@ -149,7 +_,7 @@ - int min = Math.min(state.getValue(AGE) + ageIncrement, 4); - if (this.canGrow(level, pos, state, min)) { - BlockState blockState = state.setValue(AGE, min); -- level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, blockState, Block.UPDATE_CLIENTS)) return; // Paper - if (isDouble(min)) { - level.setBlock(pos.above(), blockState.setValue(HALF, DoubleBlockHalf.UPPER), Block.UPDATE_ALL); +@@ -157,7 +_,7 @@ + int updatedAge = Math.min(lowerState.getValue(AGE) + increase, 4); + if (this.canGrow(level, lowerPos, lowerState, updatedAge)) { + BlockState newLowerState = lowerState.setValue(AGE, updatedAge); +- level.setBlock(lowerPos, newLowerState, Block.UPDATE_CLIENTS); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, lowerPos, newLowerState, Block.UPDATE_CLIENTS)) return; // Paper + if (isDouble(updatedAge)) { + level.setBlock(lowerPos.above(), newLowerState.setValue(HALF, DoubleBlockHalf.UPPER), Block.UPDATE_ALL); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch index e338e196c1fb..84d75864eb4d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch @@ -14,7 +14,7 @@ } @@ -152,7 +_,7 @@ @Override - public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, double fallDistance) { + public void fallOn(final Level level, final BlockState state, final BlockPos pos, final Entity entity, final double fallDistance) { if (state.getValue(TIP_DIRECTION) == Direction.UP && state.getValue(THICKNESS) == DripstoneThickness.TIP) { - entity.causeFallDamage(fallDistance + 2.5, 2.0F, level.damageSources().stalagmite()); + entity.causeFallDamage(fallDistance + 2.5, 2.0F, level.damageSources().stalagmite().eventBlockDamager(level, pos)); // CraftBukkit @@ -22,47 +22,47 @@ super.fallOn(level, state, pos, entity, fallDistance); } @@ -210,10 +_,11 @@ - if (blockPos != null) { - if (fluidAboveStalactite.get().sourceState.is(Blocks.MUD) && fluid == Fluids.WATER) { - BlockState blockState = Blocks.CLAY.defaultBlockState(); -- level.setBlockAndUpdate(fluidAboveStalactite.get().pos, blockState); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, fluidAboveStalactite.get().pos, blockState, Block.UPDATE_ALL)) { // Paper - Call BlockFormEvent - Block.pushEntitiesUp(fluidAboveStalactite.get().sourceState, blockState, level, fluidAboveStalactite.get().pos); - level.gameEvent(GameEvent.BLOCK_CHANGE, fluidAboveStalactite.get().pos, GameEvent.Context.of(blockState)); - level.levelEvent(LevelEvent.DRIPSTONE_DRIP, blockPos, 0); + if (stalactiteTipPos != null) { + if (fluidInfo.get().sourceState.is(Blocks.MUD) && fluid == Fluids.WATER) { + BlockState newState = Blocks.CLAY.defaultBlockState(); +- level.setBlockAndUpdate(fluidInfo.get().pos, newState); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, fluidInfo.get().pos, newState, Block.UPDATE_ALL)) { // Paper - Call BlockFormEvent + Block.pushEntitiesUp(fluidInfo.get().sourceState, newState, level, fluidInfo.get().pos); + level.gameEvent(GameEvent.BLOCK_CHANGE, fluidInfo.get().pos, GameEvent.Context.of(newState)); + level.levelEvent(LevelEvent.DRIPSTONE_DRIP, stalactiteTipPos, 0); + } // Paper - Call BlockFormEvent } else { - BlockPos blockPos1 = findFillableCauldronBelowStalactiteTip(level, blockPos, fluid); - if (blockPos1 != null) { -@@ -357,17 +_,17 @@ - if (isUnmergedTipWithDirection(blockState, direction.getOpposite())) { - createMergedTips(blockState, server, blockPos); - } else if (blockState.isAir() || blockState.is(Blocks.WATER)) { -- createDripstone(server, blockPos, direction, DripstoneThickness.TIP); -+ createDripstone(server, blockPos, direction, DripstoneThickness.TIP, pos); // CraftBukkit + BlockPos cauldronPos = findFillableCauldronBelowStalactiteTip(level, stalactiteTipPos, fluid); + if (cauldronPos != null) { +@@ -359,17 +_,17 @@ + if (isUnmergedTipWithDirection(existingStateAtTargetPos, growToDirection.getOpposite())) { + createMergedTips(existingStateAtTargetPos, level, targetPos); + } else if (existingStateAtTargetPos.isAir() || existingStateAtTargetPos.is(Blocks.WATER)) { +- createDripstone(level, targetPos, growToDirection, DripstoneThickness.TIP); ++ createDripstone(level, targetPos, growToDirection, DripstoneThickness.TIP, growFromPos); // CraftBukkit } } -- private static void createDripstone(LevelAccessor level, BlockPos pos, Direction direction, DripstoneThickness thickness) { -+ private static void createDripstone(LevelAccessor level, BlockPos pos, Direction direction, DripstoneThickness thickness, BlockPos source) { // CraftBukkit - BlockState blockState = Blocks.POINTED_DRIPSTONE +- private static void createDripstone(final LevelAccessor level, final BlockPos pos, final Direction direction, final DripstoneThickness thickness) { ++ private static void createDripstone(final LevelAccessor level, final BlockPos pos, final Direction direction, final DripstoneThickness thickness, final BlockPos source) { // CraftBukkit + BlockState state = Blocks.POINTED_DRIPSTONE .defaultBlockState() .setValue(TIP_DIRECTION, direction) .setValue(THICKNESS, thickness) - .setValue(WATERLOGGED, level.getFluidState(pos).getType() == Fluids.WATER); -- level.setBlock(pos, blockState, Block.UPDATE_ALL); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, pos, blockState, Block.UPDATE_ALL); // CraftBukkit + .setValue(WATERLOGGED, level.getFluidState(pos).is(Fluids.WATER)); +- level.setBlock(pos, state, Block.UPDATE_ALL); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, pos, state, Block.UPDATE_ALL); // CraftBukkit } - private static void createMergedTips(BlockState state, LevelAccessor level, BlockPos pos) { -@@ -381,8 +_,8 @@ - blockPos = pos.below(); + private static void createMergedTips(final BlockState tipState, final LevelAccessor level, final BlockPos tipPos) { +@@ -383,8 +_,8 @@ + stalagmitePos = tipPos.below(); } -- createDripstone(level, blockPos1, Direction.DOWN, DripstoneThickness.TIP_MERGE); -- createDripstone(level, blockPos, Direction.UP, DripstoneThickness.TIP_MERGE); -+ createDripstone(level, blockPos1, Direction.DOWN, DripstoneThickness.TIP_MERGE, pos); // CraftBukkit -+ createDripstone(level, blockPos, Direction.UP, DripstoneThickness.TIP_MERGE, pos); // CraftBukkit +- createDripstone(level, stalactitePos, Direction.DOWN, DripstoneThickness.TIP_MERGE); +- createDripstone(level, stalagmitePos, Direction.UP, DripstoneThickness.TIP_MERGE); ++ createDripstone(level, stalactitePos, Direction.DOWN, DripstoneThickness.TIP_MERGE, tipPos); // CraftBukkit ++ createDripstone(level, stalagmitePos, Direction.UP, DripstoneThickness.TIP_MERGE, tipPos); // CraftBukkit } - public static void spawnDripParticle(Level level, BlockPos pos, BlockState state) { + public static void spawnDripParticle(final Level level, final BlockPos stalactiteTipPos, final BlockState stalactiteTipState) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PowderSnowBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PowderSnowBlock.java.patch index fb6700ff7d0e..95637c475007 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PowderSnowBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PowderSnowBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/PowderSnowBlock.java +++ b/net/minecraft/world/level/block/PowderSnowBlock.java -@@ -60,6 +_,14 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -67,6 +_,14 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + // Paper start - Add EntityInsideBlockEvent + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { + if (entity instanceof net.minecraft.server.level.ServerPlayer player) { @@ -15,18 +15,18 @@ if (!(entity instanceof LivingEntity) || entity.getInBlockState().is(this)) { entity.makeStuckInBlock(state, new Vec3(0.9F, 1.5, 0.9F)); if (level.isClientSide()) { -@@ -85,8 +_,13 @@ - entity1 -> { +@@ -92,8 +_,13 @@ + e -> { if (level instanceof ServerLevel serverLevel - && entity1.isOnFire() -- && (serverLevel.getGameRules().get(GameRules.MOB_GRIEFING) || entity1 instanceof Player) + && e.isOnFire() +- && (serverLevel.getGameRules().get(GameRules.MOB_GRIEFING) || e instanceof Player) + // CraftBukkit - move down - && entity1.mayInteract(serverLevel, blockPos)) { + && e.mayInteract(serverLevel, position)) { + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity1, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().get(GameRules.MOB_GRIEFING) || entity1 instanceof Player))) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(e, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().get(GameRules.MOB_GRIEFING) || e instanceof Player))) { + return; + } + // CraftBukkit end - level.destroyBlock(blockPos, false); + level.destroyBlock(position, false); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch index dcc5b44fbbe8..2dad015f8004 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch @@ -3,14 +3,14 @@ @@ -127,6 +_,13 @@ || this.findPoweredRailSignal(level, pos, state, true, 0) || this.findPoweredRailSignal(level, pos, state, false, 0); - if (flag != poweredValue) { + if (shouldPower != isPowered) { + // CraftBukkit start -+ int power = flag ? 15 : 0; ++ int power = shouldPower ? 15 : 0; + int newPower = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, power, 15 - power).getNewCurrent(); + if (newPower == power) { + return; + } + // CraftBukkit end - level.setBlock(pos, state.setValue(POWERED, flag), Block.UPDATE_ALL); + level.setBlock(pos, state.setValue(POWERED, shouldPower), Block.UPDATE_ALL); level.updateNeighborsAt(pos.below(), this); if (state.getValue(SHAPE).isSlope()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PressurePlateBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PressurePlateBlock.java.patch index d813220d2047..8085e80d8835 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PressurePlateBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PressurePlateBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/PressurePlateBlock.java +++ b/net/minecraft/world/level/block/PressurePlateBlock.java -@@ -46,7 +_,29 @@ +@@ -45,7 +_,29 @@ case EVERYTHING -> Entity.class; case MOBS -> LivingEntity.class; }; -- return getEntityCount(level, TOUCH_AABB.move(pos), clazz) > 0 ? 15 : 0; +- return getEntityCount(level, TOUCH_AABB.move(pos), entityClass) > 0 ? 15 : 0; + // CraftBukkit start - Call interact event when turning on a pressure plate -+ for (Entity entity : getEntities(level, PressurePlateBlock.TOUCH_AABB.move(pos), clazz)) { ++ for (Entity entity : getEntities(level, PressurePlateBlock.TOUCH_AABB.move(pos), entityClass)) { + if (this.getSignalForState(level.getBlockState(pos)) == 0) { + org.bukkit.event.Cancellable cancellable; + diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PumpkinBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PumpkinBlock.java.patch index 3b1123b07c12..e92d5d86e58a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PumpkinBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PumpkinBlock.java.patch @@ -1,44 +1,46 @@ --- a/net/minecraft/world/level/block/PumpkinBlock.java +++ b/net/minecraft/world/level/block/PumpkinBlock.java -@@ -41,6 +_,7 @@ +@@ -48,6 +_,7 @@ } else if (level instanceof ServerLevel serverLevel) { - Direction direction = hitResult.getDirection(); - Direction direction1 = direction.getAxis() == Direction.Axis.Y ? player.getDirection().getOpposite() : direction; + Direction clickedDirection = hitResult.getDirection(); + Direction direction = clickedDirection.getAxis() == Direction.Axis.Y ? player.getDirection().getOpposite() : clickedDirection; + java.util.List drops = new java.util.ArrayList<>(); // Paper dropFromBlockInteractLootTable( serverLevel, BuiltInLootTables.CARVE_PUMPKIN, -@@ -49,15 +_,26 @@ - stack, +@@ -56,16 +_,27 @@ + itemStack, player, - (serverLevel1, itemStack) -> { -- ItemEntity itemEntity = new ItemEntity( -- level, pos.getX() + 0.5 + direction1.getStepX() * 0.65, pos.getY() + 0.1, pos.getZ() + 0.5 + direction1.getStepZ() * 0.65, itemStack + (ignored, pumpkinSeeds) -> { +- ItemEntity entity = new ItemEntity( +- level, pos.getX() + 0.5 + direction.getStepX() * 0.65, pos.getY() + 0.1, pos.getZ() + 0.5 + direction.getStepZ() * 0.65, pumpkinSeeds - ); -- itemEntity.setDeltaMovement( -- 0.05 * direction1.getStepX() + level.random.nextDouble() * 0.02, 0.05, 0.05 * direction1.getStepZ() + level.random.nextDouble() * 0.02 +- RandomSource random = level.getRandom(); +- entity.setDeltaMovement( +- 0.05 * direction.getStepX() + random.nextDouble() * 0.02, 0.05, 0.05 * direction.getStepZ() + random.nextDouble() * 0.02 - ); -- level.addFreshEntity(itemEntity); -+ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack)); // Paper - move spawn logic after event call +- level.addFreshEntity(entity); ++ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(pumpkinSeeds)); // Paper - move spawn logic after event call } ); + // Paper start - Add PlayerShearBlockEvent + io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent( -+ (org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), drops); ++ (org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), drops); + if (!event.callEvent()) { + return InteractionResult.PASS; + } -+ for (org.bukkit.inventory.ItemStack itemStack : event.getDrops()) { ++ for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { + // moved from above -+ ItemEntity itemEntity = new ItemEntity( -+ level, pos.getX() + 0.5 + direction1.getStepX() * 0.65, pos.getY() + 0.1, pos.getZ() + 0.5 + direction1.getStepZ() * 0.65, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(itemStack) ++ ItemEntity entity = new ItemEntity( ++ level, pos.getX() + 0.5 + direction.getStepX() * 0.65, pos.getY() + 0.1, pos.getZ() + 0.5 + direction.getStepZ() * 0.65, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(stack) + ); -+ itemEntity.setDeltaMovement( -+ 0.05 * direction1.getStepX() + level.random.nextDouble() * 0.02, 0.05, 0.05 * direction1.getStepZ() + level.random.nextDouble() * 0.02 ++ RandomSource random = level.getRandom(); ++ entity.setDeltaMovement( ++ 0.05 * direction.getStepX() + random.nextDouble() * 0.02, 0.05, 0.05 * direction.getStepZ() + random.nextDouble() * 0.02 + ); -+ level.addFreshEntity(itemEntity); ++ level.addFreshEntity(entity); + } + // Paper end - Add PlayerShearBlockEvent level.playSound(null, pos, SoundEvents.PUMPKIN_CARVE, SoundSource.BLOCKS, 1.0F, 1.0F); - level.setBlock(pos, Blocks.CARVED_PUMPKIN.defaultBlockState().setValue(CarvedPumpkinBlock.FACING, direction1), Block.UPDATE_ALL_IMMEDIATE); - stack.hurtAndBreak(1, player, hand.asEquipmentSlot()); + level.setBlock(pos, Blocks.CARVED_PUMPKIN.defaultBlockState().setValue(CarvedPumpkinBlock.FACING, direction), Block.UPDATE_ALL_IMMEDIATE); + itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch index ab0b98fd47f4..c5e80cae49a3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch @@ -10,24 +10,24 @@ + } + // Paper end - Fix some rails connecting improperly + - public RailState(Level level, BlockPos pos, BlockState state) { + public RailState(final Level level, final BlockPos pos, final BlockState state) { this.level = level; this.pos = pos; @@ -140,6 +_,11 @@ } - private void connectTo(RailState state) { + private void connectTo(final RailState rail) { + // Paper start - Fix some rails connecting improperly -+ if (!this.isValid() || !state.isValid()) { ++ if (!this.isValid() || !rail.isValid()) { + return; + } + // Paper end - Fix some rails connecting improperly - this.connections.add(state.pos); - BlockPos blockPos = this.pos.north(); - BlockPos blockPos1 = this.pos.south(); + this.connections.add(rail.pos); + BlockPos north = this.pos.north(); + BlockPos south = this.pos.south(); @@ -330,10 +_,15 @@ - this.state = this.state.setValue(this.block.getShapeProperty(), railShape); - if (alwaysPlace || this.level.getBlockState(this.pos) != this.state) { + this.state = this.state.setValue(this.block.getShapeProperty(), shape); + if (first || this.level.getBlockState(this.pos) != this.state) { this.level.setBlock(this.pos, this.state, Block.UPDATE_ALL); + // Paper start - Fix some rails connecting improperly + if (!this.isValid()) { @@ -36,12 +36,12 @@ + // Paper end - Fix some rails connecting improperly for (int i = 0; i < this.connections.size(); i++) { - RailState rail = this.getRail(this.connections.get(i)); -- if (rail != null) { -+ if (rail != null && rail.isValid()) { // Paper - Fix some rails connecting improperly - rail.removeSoftConnections(); - if (rail.canConnectTo(this)) { - rail.connectTo(this); + RailState neighbor = this.getRail(this.connections.get(i)); +- if (neighbor != null) { ++ if (neighbor != null && neighbor.isValid()) { // Paper - Fix some rails connecting improperly + neighbor.removeSoftConnections(); + if (neighbor.canConnectTo(this)) { + neighbor.connectTo(this); @@ -346,6 +_,6 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch index 43b482cd10e6..674f031b2fca 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch @@ -1,50 +1,49 @@ --- a/net/minecraft/world/level/block/RedStoneOreBlock.java +++ b/net/minecraft/world/level/block/RedStoneOreBlock.java -@@ -37,14 +_,27 @@ +@@ -37,14 +_,26 @@ @Override - protected void attack(BlockState state, Level level, BlockPos pos, Player player) { + protected void attack(final BlockState state, final Level level, final BlockPos pos, final Player player) { - interact(state, level, pos); -+ interact(state, level, pos, player); // CraftBukkit - add entityhuman ++ interact(state, level, pos, player); // CraftBukkit - add player super.attack(state, level, pos, player); } @Override - public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { + public void stepOn(final Level level, final BlockPos pos, final BlockState onState, final Entity entity) { if (!entity.isSteppingCarefully()) { -- interact(state, level, pos); +- interact(onState, level, pos); + // CraftBukkit start + if (entity instanceof Player player) { + org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null); + if (!event.isCancelled()) { -+ RedStoneOreBlock.interact(level.getBlockState(pos), level, pos, entity); // add entity ++ interact(level.getBlockState(pos), level, pos, entity); // add entity + } + } else { + org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)); -+ level.getCraftServer().getPluginManager().callEvent(event); -+ if (!event.isCancelled()) { -+ RedStoneOreBlock.interact(level.getBlockState(pos), level, pos, entity); // add entity ++ if (!event.callEvent()) { ++ interact(level.getBlockState(pos), level, pos, entity); // add entity + } + } + // CraftBukkit end } - super.stepOn(level, pos, state, entity); -@@ -57,7 +_,7 @@ + super.stepOn(level, pos, onState, entity); +@@ -63,7 +_,7 @@ if (level.isClientSide()) { spawnParticles(level, pos); } else { - interact(state, level, pos); -+ interact(state, level, pos, player); // CraftBukkit - add entityhuman ++ interact(state, level, pos, player); // CraftBukkit - add player } - return (InteractionResult)(stack.getItem() instanceof BlockItem && new BlockPlaceContext(player, hand, stack, hitResult).canPlace() -@@ -65,9 +_,14 @@ + return (InteractionResult)(itemStack.getItem() instanceof BlockItem && new BlockPlaceContext(player, hand, itemStack, hitResult).canPlace() +@@ -71,9 +_,14 @@ : InteractionResult.SUCCESS); } -- private static void interact(BlockState state, Level level, BlockPos pos) { -+ private static void interact(BlockState state, Level level, BlockPos pos, Entity entity) { // CraftBukkit - add Entity +- private static void interact(final BlockState state, final Level level, final BlockPos pos) { ++ private static void interact(final BlockState state, final Level level, final BlockPos pos, final Entity entity) { // CraftBukkit - add entity spawnParticles(level, pos); if (!state.getValue(LIT)) { + // CraftBukkit start @@ -55,9 +54,9 @@ level.setBlock(pos, state.setValue(LIT, true), Block.UPDATE_ALL); } } -@@ -80,6 +_,11 @@ +@@ -86,6 +_,11 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (state.getValue(LIT)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, state.setValue(RedStoneOreBlock.LIT, false)).isCancelled()) { @@ -67,18 +66,18 @@ level.setBlock(pos, state.setValue(LIT, false), Block.UPDATE_ALL); } } -@@ -87,9 +_,17 @@ +@@ -93,9 +_,17 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegated to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack tool, boolean dropExperience) { if (dropExperience) { -- this.tryDropExperience(level, pos, stack, UniformInt.of(1, 5)); -+ return this.tryDropExperience(level, pos, stack, UniformInt.of(1, 5)); +- this.tryDropExperience(level, pos, tool, UniformInt.of(1, 5)); ++ return this.tryDropExperience(level, pos, tool, UniformInt.of(1, 5)); } + + return 0; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneLampBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneLampBlock.java.patch index 652ca91bea10..e23c1484d01a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneLampBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneLampBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/RedstoneLampBlock.java +++ b/net/minecraft/world/level/block/RedstoneLampBlock.java -@@ -40,6 +_,11 @@ - if (litValue) { +@@ -42,6 +_,11 @@ + if (isLit) { level.scheduleTick(pos, this, 4); } else { + // CraftBukkit start @@ -12,9 +12,9 @@ level.setBlock(pos, state.cycle(LIT), Block.UPDATE_CLIENTS); } } -@@ -49,6 +_,11 @@ +@@ -51,6 +_,11 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (state.getValue(LIT) && !level.hasNeighborSignal(pos)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneTorchBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneTorchBlock.java.patch index 86fdd6576331..5f9acf772ed3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneTorchBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RedstoneTorchBlock.java.patch @@ -9,38 +9,35 @@ public static final int RECENT_TOGGLE_TIMER = 60; public static final int MAX_RECENT_TOGGLES = 8; public static final int RESTART_DELAY = 160; -@@ -72,14 +_,34 @@ +@@ -72,14 +_,32 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - boolean hasNeighborSignal = this.hasNeighborSignal(level, pos, state); -- List list = RECENT_TOGGLES.get(level); + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + boolean neighborSignal = this.hasNeighborSignal(level, pos, state); +- List toggles = RECENT_TOGGLES.get(level); - -- while (list != null && !list.isEmpty() && level.getGameTime() - list.get(0).when > 60L) { -- list.remove(0); +- while (toggles != null && !toggles.isEmpty() && level.getGameTime() - toggles.get(0).when > 60L) { +- toggles.remove(0); + // Paper start - Faster redstone torch rapid clock removal -+ java.util.ArrayDeque redstoneUpdateInfos = level.redstoneUpdateInfos; -+ if (redstoneUpdateInfos != null) { ++ java.util.ArrayDeque toggles = level.redstoneUpdateInfos; ++ if (toggles != null) { + RedstoneTorchBlock.Toggle curr; -+ while ((curr = redstoneUpdateInfos.peek()) != null && level.getGameTime() - curr.when > 60L) { -+ redstoneUpdateInfos.poll(); ++ while ((curr = toggles.peek()) != null && level.getGameTime() - curr.when > 60L) { ++ toggles.poll(); + } } -- + // Paper end - Faster redstone torch rapid clock removal -+ + // CraftBukkit start -+ org.bukkit.plugin.PluginManager manager = level.getCraftServer().getPluginManager(); + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + int oldCurrent = state.getValue(LIT) ? 15 : 0; -+ + + org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(block, oldCurrent, oldCurrent); + // CraftBukkit end if (state.getValue(LIT)) { - if (hasNeighborSignal) { + if (neighborSignal) { + // CraftBukkit start + if (oldCurrent != 0) { + event.setNewCurrent(0); -+ manager.callEvent(event); ++ event.callEvent(); + if (event.getNewCurrent() != 0) { + return; + } @@ -52,11 +49,11 @@ @@ -87,6 +_,15 @@ } } - } else if (!hasNeighborSignal && !isToggledTooFrequently(level, pos, false)) { + } else if (!neighborSignal && !isToggledTooFrequently(level, pos, false)) { + // CraftBukkit start + if (oldCurrent != 15) { + event.setNewCurrent(15); -+ manager.callEvent(event); ++ event.callEvent(); + if (event.getNewCurrent() != 15) { + return; + } @@ -65,17 +62,17 @@ level.setBlock(pos, state.setValue(LIT, true), Block.UPDATE_ALL); } } -@@ -124,7 +_,12 @@ +@@ -126,7 +_,12 @@ } - private static boolean isToggledTooFrequently(Level level, BlockPos pos, boolean logToggle) { -- List list = RECENT_TOGGLES.computeIfAbsent(level, blockGetter -> Lists.newArrayList()); + private static boolean isToggledTooFrequently(final Level level, final BlockPos pos, final boolean add) { +- List toggles = RECENT_TOGGLES.computeIfAbsent(level, k -> Lists.newArrayList()); + // Paper start - Faster redstone torch rapid clock removal -+ java.util.ArrayDeque list = level.redstoneUpdateInfos; -+ if (list == null) { -+ list = level.redstoneUpdateInfos = new java.util.ArrayDeque<>(); ++ java.util.ArrayDeque toggles = level.redstoneUpdateInfos; ++ if (toggles == null) { ++ toggles = level.redstoneUpdateInfos = new java.util.ArrayDeque<>(); + } + // Paper end - Faster redstone torch rapid clock removal - if (logToggle) { - list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), level.getGameTime())); + if (add) { + toggles.add(new RedstoneTorchBlock.Toggle(pos.immutable(), level.getGameTime())); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch index 392898ca5c6f..a7de8dc2e270 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/RespawnAnchorBlock.java +++ b/net/minecraft/world/level/block/RespawnAnchorBlock.java -@@ -106,11 +_,16 @@ +@@ -115,11 +_,16 @@ LevelData.RespawnData.of(serverLevel.dimension(), pos, 0.0F, 0.0F), false ); - if (respawnConfig == null || !respawnConfig.isSamePosition(respawnConfig1)) { -- serverPlayer.setRespawnPosition(respawnConfig1, true); -+ if (serverPlayer.setRespawnPosition(respawnConfig1, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { // Paper - Add PlayerSetSpawnEvent + if (respawnConfig == null || !respawnConfig.isSamePosition(newRespawnConfig)) { +- serverPlayer.setRespawnPosition(newRespawnConfig, true); ++ if (serverPlayer.setRespawnPosition(newRespawnConfig, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { // Paper - Add PlayerSetSpawnEvent serverLevel.playSound( null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, SoundEvents.RESPAWN_ANCHOR_SET_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F ); @@ -18,20 +18,20 @@ } } -@@ -147,6 +_,7 @@ +@@ -156,6 +_,7 @@ } - private void explode(BlockState state, ServerLevel level, final BlockPos pos2) { -+ org.bukkit.block.BlockState blockState = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos2).getState(); // CraftBukkit - capture BlockState before remove block - level.removeBlock(pos2, false); - boolean flag = Direction.Plane.HORIZONTAL.stream().map(pos2::relative).anyMatch(blockPos -> isWaterThatWouldFlow(blockPos, level)); - final boolean flag1 = flag || level.getFluidState(pos2.above()).is(FluidTags.WATER); -@@ -160,7 +_,7 @@ + private void explode(final BlockState state, final ServerLevel level, final BlockPos pos) { ++ org.bukkit.block.BlockState blockState = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos).getState(); // CraftBukkit - capture BlockState before remove block + level.removeBlock(pos, false); + boolean anyWaterNeighbors = Direction.Plane.HORIZONTAL.stream().map(pos::relative).anyMatch(neighborPos -> isWaterThatWouldFlow(neighborPos, level)); + final boolean inWater = anyWaterNeighbors || level.getFluidState(pos.above()).is(FluidTags.WATER); +@@ -174,7 +_,7 @@ + } }; - Vec3 center = pos2.getCenter(); - level.explode( -- null, level.damageSources().badRespawnPointExplosion(center), explosionDamageCalculator, center, 5.0F, true, Level.ExplosionInteraction.BLOCK -+ null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), explosionDamageCalculator, center, 5.0F, true, Level.ExplosionInteraction.BLOCK // CraftBukkit - add state - ); + Vec3 boomPos = pos.getCenter(); +- level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos), damageCalculator, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); ++ level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos).causingBlockSnapshot(blockState), damageCalculator, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state } + public static boolean canSetSpawn(final ServerLevel level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RootedDirtBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RootedDirtBlock.java.patch index 508e289bb713..0be20be17351 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RootedDirtBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RootedDirtBlock.java.patch @@ -3,7 +3,7 @@ @@ -33,7 +_,7 @@ @Override - public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + public void performBonemeal(final ServerLevel level, final RandomSource random, final BlockPos pos, final BlockState state) { - level.setBlockAndUpdate(pos.below(), Blocks.HANGING_ROOTS.defaultBlockState()); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, pos.below(), Blocks.HANGING_ROOTS.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SaplingBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SaplingBlock.java.patch index d6efefbb6639..0500e2141d60 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SaplingBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SaplingBlock.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/level/block/SaplingBlock.java +++ b/net/minecraft/world/level/block/SaplingBlock.java -@@ -25,6 +_,7 @@ +@@ -24,6 +_,7 @@ public static final IntegerProperty STAGE = BlockStateProperties.STAGE; private static final VoxelShape SHAPE = Block.column(12.0, 0.0, 12.0); protected final TreeGrower treeGrower; -+ public static @javax.annotation.Nullable org.bukkit.TreeType treeType; // CraftBukkit ++ public static org.bukkit.@org.jspecify.annotations.Nullable TreeType treeType; // CraftBukkit @Override public MapCodec codec() { -@@ -44,7 +_,7 @@ +@@ -43,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { - if (level.getMaxLocalRawBrightness(pos.above()) >= 9 && random.nextInt(7) == 0) { + if (level.getMaxLocalRawBrightness(pos.above()) >= 9 && random.nextFloat() < (level.spigotConfig.saplingModifier / (100.0F * 7))) { // Spigot - SPIGOT-7159: Better modifier resolution this.advanceTree(level, pos, state, random); } } -@@ -53,7 +_,34 @@ +@@ -52,7 +_,34 @@ if (state.getValue(STAGE) == 0) { level.setBlock(pos, state.cycle(STAGE), Block.UPDATE_NONE); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ScaffoldingBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ScaffoldingBlock.java.patch index ab3df7b7e118..5a7081bee284 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ScaffoldingBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ScaffoldingBlock.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/ScaffoldingBlock.java +++ b/net/minecraft/world/level/block/ScaffoldingBlock.java @@ -117,7 +_,7 @@ - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { int distance = getDistance(level, pos); - BlockState blockState = state.setValue(DISTANCE, distance).setValue(BOTTOM, this.isBottom(level, pos, distance)); -- if (blockState.getValue(DISTANCE) == 7) { -+ if (blockState.getValue(DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, blockState.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit - BlockFadeEvent // Paper - fix wrong block state + BlockState newState = state.setValue(DISTANCE, distance).setValue(BOTTOM, this.isBottom(level, pos, distance)); +- if (newState.getValue(DISTANCE) == 7) { ++ if (newState.getValue(DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, newState.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit - BlockFadeEvent // Paper - fix wrong block state if (state.getValue(DISTANCE) == 7) { - FallingBlockEntity.fall(level, pos, blockState); + FallingBlockEntity.fall(level, pos, newState); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkBlock.java.patch index d66b40184d7d..866bae4bf2d9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkBlock.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/level/block/SculkBlock.java +++ b/net/minecraft/world/level/block/SculkBlock.java -@@ -37,8 +_,9 @@ - if (random.nextInt(growthSpawnCost) < charge) { - BlockPos blockPos = pos1.above(); - BlockState randomGrowthState = this.getRandomGrowthState(level, blockPos, random, spreader.isWorldGeneration()); -- level.setBlock(blockPos, randomGrowthState, Block.UPDATE_ALL); -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, randomGrowthState, Block.UPDATE_ALL)) { // CraftBukkit - Call BlockSpreadEvent - level.playSound(null, pos1, randomGrowthState.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0F, 1.0F); +@@ -42,8 +_,9 @@ + if (random.nextInt(xpPerGrowthSpawn) < charge) { + BlockPos growthPlacement = chargePos.above(); + BlockState growthState = this.getRandomGrowthState(level, growthPlacement, random, spreader.isWorldGeneration()); +- level.setBlock(growthPlacement, growthState, Block.UPDATE_ALL); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, originPos, growthPlacement, growthState, Block.UPDATE_ALL)) { // CraftBukkit - Call BlockSpreadEvent + level.playSound(null, chargePos, growthState.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0F, 1.0F); + } // CraftBukkit - Call BlockSpreadEvent } - return Math.max(0, charge - growthSpawnCost); + return Math.max(0, charge - xpPerGrowthSpawn); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkCatalystBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkCatalystBlock.java.patch index b3c120dc3f1d..3cfe30ec4e29 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkCatalystBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkCatalystBlock.java.patch @@ -2,20 +2,19 @@ +++ b/net/minecraft/world/level/block/SculkCatalystBlock.java @@ -59,8 +_,16 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegate to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack tool, boolean dropExperience) { if (dropExperience) { -- this.tryDropExperience(level, pos, stack, this.xpRange); -+ return this.tryDropExperience(level, pos, stack, this.xpRange); +- this.tryDropExperience(level, pos, tool, this.xpRange); ++ return this.tryDropExperience(level, pos, tool, this.xpRange); } -- } + + return 0; + // CraftBukkit end -+ } + } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkSensorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkSensorBlock.java.patch index 92ddd79a9fd1..9a00eac56c70 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkSensorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkSensorBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/SculkSensorBlock.java +++ b/net/minecraft/world/level/block/SculkSensorBlock.java @@ -101,6 +_,18 @@ - && level.getBlockEntity(pos) instanceof SculkSensorBlockEntity sculkSensorBlockEntity + && level.getBlockEntity(pos) instanceof SculkSensorBlockEntity sculkSensor && level instanceof ServerLevel serverLevel - && sculkSensorBlockEntity.getVibrationUser().canReceiveVibration(serverLevel, pos, GameEvent.STEP, GameEvent.Context.of(state))) { + && sculkSensor.getVibrationUser().canReceiveVibration(serverLevel, pos, GameEvent.STEP, GameEvent.Context.of(onState))) { + // CraftBukkit start + org.bukkit.event.Cancellable cancellable; + if (entity instanceof net.minecraft.world.entity.player.Player player) { @@ -16,18 +16,18 @@ + return; + } + // CraftBukkit end - sculkSensorBlockEntity.getListener().forceScheduleVibration(serverLevel, GameEvent.STEP, GameEvent.Context.of(entity), entity.position()); + sculkSensor.getListener().forceScheduleVibration(serverLevel, GameEvent.STEP, GameEvent.Context.of(entity), entity.position()); } @@ -188,10 +_,19 @@ } - public static boolean canActivate(BlockState state) { + public static boolean canActivate(final BlockState state) { - return getPhase(state) == SculkSensorPhase.INACTIVE; -+ return state.getBlock() instanceof SculkSensorBlock && getPhase(state) == SculkSensorPhase.INACTIVE; // Paper - Check for a valid type ++ return state.getBlock() instanceof SculkSensorBlock && getPhase(state) == SculkSensorPhase.INACTIVE; // Paper - Check for a valid type } - public static void deactivate(Level level, BlockPos pos, BlockState state) { + public static void deactivate(final Level level, final BlockPos pos, final BlockState state) { + // CraftBukkit start + org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.getValue(SculkSensorBlock.POWER), 0); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); @@ -40,34 +40,38 @@ level.setBlock(pos, state.setValue(PHASE, SculkSensorPhase.COOLDOWN).setValue(POWER, 0), Block.UPDATE_ALL); level.scheduleTick(pos, state.getBlock(), 10); updateNeighbours(level, pos, state); -@@ -203,6 +_,15 @@ - } - - public void activate(@Nullable Entity entity, Level level, BlockPos pos, BlockState state, int power, int frequency) { +@@ -207,9 +_,18 @@ + final Level level, + final BlockPos pos, + final BlockState state, +- final int calculatedPower, ++ int calculatedPower, // CraftBukkit + final int vibrationFrequency + ) { + // CraftBukkit start -+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.getValue(SculkSensorBlock.POWER), power); ++ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.getValue(SculkSensorBlock.POWER), calculatedPower); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); + + if (eventRedstone.getNewCurrent() <= 0) { + return; + } -+ power = eventRedstone.getNewCurrent(); ++ calculatedPower = eventRedstone.getNewCurrent(); + // CraftBukkit end - level.setBlock(pos, state.setValue(PHASE, SculkSensorPhase.ACTIVE).setValue(POWER, power), Block.UPDATE_ALL); + level.setBlock(pos, state.setValue(PHASE, SculkSensorPhase.ACTIVE).setValue(POWER, calculatedPower), Block.UPDATE_ALL); level.scheduleTick(pos, state.getBlock(), this.getActiveTicks()); updateNeighbours(level, pos, state); -@@ -280,8 +_,16 @@ +@@ -287,8 +_,16 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegate to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { if (dropExperience) { -- this.tryDropExperience(level, pos, stack, ConstantInt.of(5)); -+ return this.tryDropExperience(level, pos, stack, ConstantInt.of(5)); +- this.tryDropExperience(level, pos, tool, ConstantInt.of(5)); ++ return this.tryDropExperience(level, pos, tool, ConstantInt.of(5)); } + + return 0; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch index 3bd01d8b8855..22527605c07a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch @@ -2,24 +2,24 @@ +++ b/net/minecraft/world/level/block/SculkShriekerBlock.java @@ -60,6 +_,7 @@ if (level instanceof ServerLevel serverLevel) { - ServerPlayer serverPlayer = SculkShriekerBlockEntity.tryGetPlayer(entity); - if (serverPlayer != null) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(serverPlayer, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null).isCancelled()) return; // CraftBukkit - serverLevel.getBlockEntity(pos, BlockEntityType.SCULK_SHRIEKER).ifPresent(sculkShrieker -> sculkShrieker.tryShriek(serverLevel, serverPlayer)); + ServerPlayer player = SculkShriekerBlockEntity.tryGetPlayer(entity); + if (player != null) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null).isCancelled()) return; // CraftBukkit + serverLevel.getBlockEntity(pos, BlockEntityType.SCULK_SHRIEKER).ifPresent(shrieker -> shrieker.tryShriek(serverLevel, player)); } } @@ -126,9 +_,16 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegate to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { if (dropExperience) { -- this.tryDropExperience(level, pos, stack, ConstantInt.of(5)); -+ return this.tryDropExperience(level, pos, stack, ConstantInt.of(5)); +- this.tryDropExperience(level, pos, tool, ConstantInt.of(5)); ++ return this.tryDropExperience(level, pos, tool, ConstantInt.of(5)); } + return 0; + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkSpreader.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkSpreader.java.patch index 067dff375749..ac2f03634176 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkSpreader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkSpreader.java.patch @@ -7,28 +7,28 @@ + public net.minecraft.world.level.Level level; // CraftBukkit public SculkSpreader( - boolean isWorldGeneration, TagKey replaceableBlocks, int growthSpawnCost, int noGrowthRadius, int chargeDecayRate, int additionalDecayRate -@@ -102,7 +_,7 @@ + final boolean isWorldGeneration, +@@ -107,7 +_,7 @@ - public void load(ValueInput input) { + public void load(final ValueInput input) { this.cursors.clear(); - input.read("cursors", SculkSpreader.ChargeCursor.CODEC.sizeLimitedListOf(32)).orElse(List.of()).forEach(this::addCursor); -+ input.read("cursors", SculkSpreader.ChargeCursor.CODEC.sizeLimitedListOf(32)).orElse(List.of()).forEach((cursor) -> this.addCursor(cursor, false)); // Paper - don't fire event for block entity loading ++ input.read("cursors", SculkSpreader.ChargeCursor.CODEC.sizeLimitedListOf(32)).orElse(List.of()).forEach((cursor) -> this.addCursor(cursor, false)); // Paper - don't fire event for block entity loading } - public void save(ValueOutput output) { -@@ -121,13 +_,24 @@ - public void addCursors(BlockPos pos, int charge) { + public void save(final ValueOutput output) { +@@ -126,13 +_,24 @@ + public void addCursors(final BlockPos startPos, int charge) { while (charge > 0) { - int min = Math.min(charge, 1000); -- this.addCursor(new SculkSpreader.ChargeCursor(pos, min)); -+ this.addCursor(new SculkSpreader.ChargeCursor(pos, min), true); // Paper - allow firing event for other causes - charge -= min; + int currentCharge = Math.min(charge, 1000); +- this.addCursor(new SculkSpreader.ChargeCursor(startPos, currentCharge)); ++ this.addCursor(new SculkSpreader.ChargeCursor(startPos, currentCharge), true); // Paper - allow firing event for other causes + charge -= currentCharge; } } -- private void addCursor(SculkSpreader.ChargeCursor cursor) { -+ private void addCursor(SculkSpreader.ChargeCursor cursor, boolean fireEvent) { // Paper - add boolean to conditionally fire SculkBloomEvent +- private void addCursor(final SculkSpreader.ChargeCursor cursor) { ++ private void addCursor(final SculkSpreader.ChargeCursor cursor, boolean fireEvent) { // Paper - add boolean to conditionally fire SculkBloomEvent if (this.cursors.size() < 32) { + // CraftBukkit start + if (!this.isWorldGeneration() && fireEvent) { // CraftBukkit - SPIGOT-7475: Don't call event during world generation // Paper - add boolean to conditionally fire SculkBloomEvent diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch index 2450b1ae9ef2..47ecdbed28b0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch @@ -1,32 +1,32 @@ --- a/net/minecraft/world/level/block/SculkVeinBlock.java +++ b/net/minecraft/world/level/block/SculkVeinBlock.java -@@ -90,14 +_,14 @@ - public int attemptUseCharge( - SculkSpreader.ChargeCursor cursor, LevelAccessor level, BlockPos pos, RandomSource random, SculkSpreader spreader, boolean shouldConvertBlocks +@@ -96,14 +_,14 @@ + final SculkSpreader spreader, + final boolean spreadVeins ) { -- if (shouldConvertBlocks && this.attemptPlaceSculk(spreader, level, cursor.getPos(), random)) { -+ if (shouldConvertBlocks && this.attemptPlaceSculk(spreader, level, cursor.getPos(), random, pos)) { // CraftBukkit - add source block +- if (spreadVeins && this.attemptPlaceSculk(spreader, level, cursor.getPos(), random)) { ++ if (spreadVeins && this.attemptPlaceSculk(spreader, level, cursor.getPos(), random, originPos)) { // CraftBukkit - add source block return cursor.getCharge() - 1; } else { return random.nextInt(spreader.chargeDecayRate()) == 0 ? Mth.floor(cursor.getCharge() * 0.5F) : cursor.getCharge(); } } -- private boolean attemptPlaceSculk(SculkSpreader spreader, LevelAccessor level, BlockPos pos, RandomSource random) { -+ private boolean attemptPlaceSculk(SculkSpreader spreader, LevelAccessor level, BlockPos pos, RandomSource random, BlockPos sourceBlock) { // CraftBukkit - BlockState blockState = level.getBlockState(pos); - TagKey tagKey = spreader.replaceableBlocks(); +- private boolean attemptPlaceSculk(final SculkSpreader spreader, final LevelAccessor level, final BlockPos pos, final RandomSource random) { ++ private boolean attemptPlaceSculk(final SculkSpreader spreader, final LevelAccessor level, final BlockPos pos, final RandomSource random, final BlockPos originPos) { // CraftBukkit + BlockState state = level.getBlockState(pos); + TagKey replaceTag = spreader.replaceableBlocks(); -@@ -107,7 +_,11 @@ - BlockState blockState1 = level.getBlockState(blockPos); - if (blockState1.is(tagKey)) { - BlockState blockState2 = Blocks.SCULK.defaultBlockState(); -- level.setBlock(blockPos, blockState2, Block.UPDATE_ALL); +@@ -113,7 +_,11 @@ + BlockState supportState = level.getBlockState(supportPos); + if (supportState.is(replaceTag)) { + BlockState defaultSculk = Blocks.SCULK.defaultBlockState(); +- level.setBlock(supportPos, defaultSculk, Block.UPDATE_ALL); + // CraftBukkit start - Call BlockSpreadEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, sourceBlock, blockPos, blockState2, Block.UPDATE_ALL)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, originPos, supportPos, defaultSculk, Block.UPDATE_ALL)) { + return false; + } + // CraftBukkit end - Block.pushEntitiesUp(blockState1, blockState2, level, blockPos); - level.playSound(null, blockPos, SoundEvents.SCULK_BLOCK_SPREAD, SoundSource.BLOCKS, 1.0F, 1.0F); - this.veinSpreader.spreadAll(blockState2, level, blockPos, spreader.isWorldGeneration()); + Block.pushEntitiesUp(supportState, defaultSculk, level, supportPos); + level.playSound(null, supportPos, SoundEvents.SCULK_BLOCK_SPREAD, SoundSource.BLOCKS, 1.0F, 1.0F); + this.veinSpreader.spreadAll(defaultSculk, level, supportPos, spreader.isWorldGeneration()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ShelfBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ShelfBlock.java.patch index 67623f8446d0..96c8916f22c0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ShelfBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ShelfBlock.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/ShelfBlock.java +++ b/net/minecraft/world/level/block/ShelfBlock.java -@@ -109,6 +_,11 @@ +@@ -111,6 +_,11 @@ if (!level.isClientSide()) { - boolean hasNeighborSignal = level.hasNeighborSignal(pos); - if (state.getValue(POWERED) != hasNeighborSignal) { + boolean signal = level.hasNeighborSignal(pos); + if (state.getValue(POWERED) != signal) { + // Paper start - Call BlockRedstoneEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, hasNeighborSignal)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) { + return; + } + // Paper end - Call BlockRedstoneEvent - BlockState blockState = state.setValue(POWERED, hasNeighborSignal); - if (!hasNeighborSignal) { - blockState = blockState.setValue(SIDE_CHAIN_PART, SideChainPart.UNCONNECTED); + BlockState newState = state.setValue(POWERED, signal); + if (!signal) { + newState = newState.setValue(SIDE_CHAIN_PART, SideChainPart.UNCONNECTED); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ShulkerBoxBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ShulkerBoxBlock.java.patch index 2173429fc874..7e59a7ff1345 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ShulkerBoxBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ShulkerBoxBlock.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/ShulkerBoxBlock.java +++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java @@ -76,8 +_,8 @@ - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + ) { if (level instanceof ServerLevel serverLevel && level.getBlockEntity(pos) instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity - && canOpen(state, level, pos, shulkerBoxBlockEntity)) { @@ -12,8 +12,8 @@ PiglinAi.angerNearbyPiglins(serverLevel, player, true); } @@ -115,7 +_,7 @@ - itemEntity.setDefaultPickUpDelay(); - level.addFreshEntity(itemEntity); + entity.setDefaultPickUpDelay(); + level.addFreshEntity(entity); } else { - shulkerBoxBlockEntity.unpackLootTable(player); + shulkerBoxBlockEntity.unpackLootTable(player, true); // Paper - force clear loot table so replenish data isn't persisted in the stack @@ -22,7 +22,7 @@ @@ -125,7 +_,15 @@ @Override - protected List getDrops(BlockState state, LootParams.Builder params) { + protected List getDrops(final BlockState state, LootParams.Builder params) { BlockEntity blockEntity = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY); + Runnable reAdd = null; // Paper if (blockEntity instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SignBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SignBlock.java.patch index 3ea7cf679255..136e9b71aa14 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SignBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SignBlock.java.patch @@ -1,27 +1,27 @@ --- a/net/minecraft/world/level/block/SignBlock.java +++ b/net/minecraft/world/level/block/SignBlock.java -@@ -133,7 +_,7 @@ - } else if (!this.otherPlayerIsEditingSign(player, signBlockEntity) - && player.mayBuild() - && this.hasEditableText(player, signBlockEntity, isFacingFrontText)) { -- this.openTextEdit(player, signBlockEntity, isFacingFrontText); -+ this.openTextEdit(player, signBlockEntity, isFacingFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.INTERACT); // Paper - Add PlayerOpenSignEvent +@@ -137,7 +_,7 @@ + } else if (executedClickCommand) { + return InteractionResult.SUCCESS_SERVER; + } else if (!this.otherPlayerIsEditingSign(player, sign) && player.mayBuild() && this.hasEditableText(player, sign, isFrontText)) { +- this.openTextEdit(player, sign, isFrontText); ++ this.openTextEdit(player, sign, isFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.INTERACT); // Paper - Add PlayerOpenSignEvent return InteractionResult.SUCCESS_SERVER; } else { return InteractionResult.PASS; -@@ -179,7 +_,34 @@ - return woodType; +@@ -176,7 +_,34 @@ + return block instanceof SignBlock signBlock ? signBlock.type() : WoodType.OAK; } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add PlayerOpenSignEvent - public void openTextEdit(Player player, SignBlockEntity signEntity, boolean isFrontText) { + public void openTextEdit(final Player player, final SignBlockEntity sign, final boolean isFrontText) { + // Paper start - Add PlayerOpenSignEvent -+ this.openTextEdit(player, signEntity, isFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.UNKNOWN); ++ this.openTextEdit(player, sign, isFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.UNKNOWN); + } + -+ public void openTextEdit(Player player, SignBlockEntity signEntity, boolean isFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause cause) { ++ public void openTextEdit(Player player, SignBlockEntity sign, boolean isFrontText, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause cause) { + org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.getBukkitEntity(); -+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(signEntity.getLevel(), signEntity.getBlockPos()); ++ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(sign.getLevel(), sign.getBlockPos()); + org.bukkit.craftbukkit.block.CraftSign bukkitSign = (org.bukkit.craftbukkit.block.CraftSign) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(bukkitBlock); + io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent( + bukkitPlayer, @@ -36,19 +36,19 @@ + case INTERACT -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT; + case UNKNOWN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN; + }; -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(player, signEntity, isFrontText, legacyCause)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(player, sign, isFrontText, legacyCause)) { + // Paper end - Add PlayerOpenSignEvent + return; + } + } // Paper - Add PlayerOpenSignEvent - signEntity.setAllowedPlayerEditor(player.getUUID()); - player.openTextEdit(signEntity, isFrontText); + sign.setAllowedPlayerEditor(player.getUUID()); + player.openTextEdit(sign, isFrontText); } -@@ -191,6 +_,6 @@ +@@ -188,6 +_,6 @@ @Override - public @Nullable BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { -- return createTickerHelper(blockEntityType, BlockEntityType.SIGN, SignBlockEntity::tick); + public @Nullable BlockEntityTicker getTicker(final Level level, final BlockState blockState, final BlockEntityType type) { +- return createTickerHelper(type, BlockEntityType.SIGN, SignBlockEntity::tick); + return null; // CraftBukkit - remove unnecessary sign ticking } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SmithingTableBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SmithingTableBlock.java.patch index a7365977a076..82af236afd5b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SmithingTableBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SmithingTableBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/SmithingTableBlock.java +++ b/net/minecraft/world/level/block/SmithingTableBlock.java -@@ -38,8 +_,9 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -40,8 +_,9 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SmokerBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SmokerBlock.java.patch index dd2321c6f79c..2c05e9127682 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SmokerBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SmokerBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/SmokerBlock.java @@ -43,8 +_,7 @@ @Override - protected void openContainer(Level level, BlockPos pos, Player player) { + protected void openContainer(final Level level, final BlockPos pos, final Player player) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof SmokerBlockEntity) { - player.openMenu((MenuProvider)blockEntity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SnifferEggBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SnifferEggBlock.java.patch index 67fde9dc3442..97b3651f8394 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SnifferEggBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SnifferEggBlock.java.patch @@ -7,36 +7,36 @@ + // Paper start - Call BlockFadeEvent + private void rescheduleTick(ServerLevel level, BlockPos pos) { + int baseDelay = hatchBoost(level, pos) ? level.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : level.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - Configure sniffer egg hatch time -+ level.scheduleTick(pos, this, (baseDelay / 3) + level.random.nextInt(RANDOM_HATCH_OFFSET_TICKS)); ++ level.scheduleTick(pos, this, (baseDelay / 3) + level.getRandom().nextInt(RANDOM_HATCH_OFFSET_TICKS)); + // reschedule to avoid being stuck here and behave like the other calls (see #onPlace) + } + // Paper end - Call BlockFadeEvent + @Override - public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + public void tick(final BlockState state, final ServerLevel level, final BlockPos position, final RandomSource random) { if (!this.isReadyToHatch(state)) { + // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(HATCH, this.getHatchLevel(state) + 1), Block.UPDATE_CLIENTS)) { -+ this.rescheduleTick(level, pos); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, position, state.setValue(HATCH, this.getHatchLevel(state) + 1), Block.UPDATE_CLIENTS)) { ++ this.rescheduleTick(level, position); + return; + } + // Paper end - level.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); -- level.setBlock(pos, state.setValue(HATCH, this.getHatchLevel(state) + 1), Block.UPDATE_CLIENTS); + level.playSound(null, position, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); +- level.setBlock(position, state.setValue(HATCH, this.getHatchLevel(state) + 1), Block.UPDATE_CLIENTS); } else { + // Paper start - Call BlockFadeEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, state.getFluidState().createLegacyBlock()).isCancelled()) { -+ this.rescheduleTick(level, pos); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, position, state.getFluidState().createLegacyBlock()).isCancelled()) { ++ this.rescheduleTick(level, position); + return; + } + // Paper end - Call BlockFadeEvent - level.playSound(null, pos, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); - level.destroyBlock(pos, false); + level.playSound(null, position, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); + level.destroyBlock(position, false); Sniffer sniffer = EntityType.SNIFFER.create(level, EntitySpawnReason.BREEDING); @@ -74,7 +_,7 @@ - Vec3 center = pos.getCenter(); + Vec3 spawnAt = position.getCenter(); sniffer.setBaby(true); - sniffer.snapTo(center.x(), center.y(), center.z(), Mth.wrapDegrees(level.random.nextFloat() * 360.0F), 0.0F); + sniffer.snapTo(spawnAt.x(), spawnAt.y(), spawnAt.z(), Mth.wrapDegrees(level.getRandom().nextFloat() * 360.0F), 0.0F); - level.addFreshEntity(sniffer); + level.addFreshEntity(sniffer, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // Paper - use correct spawn reason } @@ -46,8 +46,8 @@ level.levelEvent(LevelEvent.PARTICLES_EGG_CRACK, pos, 0); } -- int i = flag ? 12000 : 24000; -+ int i = flag ? level.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : level.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - int i1 = i / 3; +- int hatchTime = boosted ? 12000 : 24000; ++ int hatchTime = boosted ? level.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : level.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper + int progressionTickDelay = hatchTime / 3; level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(state)); - level.scheduleTick(pos, this, i1 + level.random.nextInt(300)); + level.scheduleTick(pos, this, progressionTickDelay + level.getRandom().nextInt(300)); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch index c6cb4340da02..55214cbb3832 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch @@ -2,7 +2,7 @@ +++ b/net/minecraft/world/level/block/SnowLayerBlock.java @@ -103,6 +_,11 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (level.getBrightness(LightLayer.BLOCK, pos) > 11) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch index 5dfdd1e2d92d..a6d2a1368fad 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch @@ -1,22 +1,22 @@ --- a/net/minecraft/world/level/block/SpawnerBlock.java +++ b/net/minecraft/world/level/block/SpawnerBlock.java -@@ -40,9 +_,17 @@ +@@ -39,10 +_,18 @@ @Override - protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - super.spawnAfterBreak(state, level, pos, stack, dropExperience); + protected void spawnAfterBreak(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, tool, dropExperience); + // CraftBukkit start - Delegate to getExpDrop + } + + @Override -+ public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ public int getExpDrop(final BlockState state, final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { if (dropExperience) { - int i = 15 + level.random.nextInt(15) + level.random.nextInt(15); -- this.popExperience(level, pos, i); -+ // this.popExperience(level, pos, i); -+ return i; + RandomSource random = level.getRandom(); + int magicCount = 15 + random.nextInt(15) + random.nextInt(15); +- this.popExperience(level, pos, magicCount); ++ // this.popExperience(level, pos, magicCount); ++ return magicCount; } -- } + return 0; + // CraftBukkit end -+ } + } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch index 1ce60091fb37..5389db97dab7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch @@ -1,63 +1,61 @@ --- a/net/minecraft/world/level/block/SpongeBlock.java +++ b/net/minecraft/world/level/block/SpongeBlock.java -@@ -50,7 +_,8 @@ +@@ -52,7 +_,8 @@ } - private boolean removeWaterBreadthFirstSearch(Level level, BlockPos pos) { -- return BlockPos.breadthFirstTraversal( + private boolean removeWaterBreadthFirstSearch(final Level level, final BlockPos startPos) { +- return BlockPos.breadthFirstTraversal(startPos, 6, 65, (pos, consumer) -> { + org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level); // CraftBukkit - Use BlockStateListPopulator -+ BlockPos.breadthFirstTraversal( - pos, - 6, - 65, -@@ -63,16 +_,18 @@ - if (blockPos.equals(pos)) { - return BlockPos.TraversalNodeStatus.ACCEPT; ++ BlockPos.breadthFirstTraversal(startPos, 6, 65, (pos, consumer) -> { + for (Direction direction : ALL_DIRECTIONS) { + consumer.accept(pos.relative(direction)); + } +@@ -60,28 +_,65 @@ + if (pos.equals(startPos)) { + return BlockPos.TraversalNodeStatus.ACCEPT; + } else { +- BlockState state = level.getBlockState(pos); +- FluidState fluidState = level.getFluidState(pos); ++ // CraftBukkit start ++ BlockState blockState = blockList.getBlockState(pos); ++ FluidState fluidState = blockList.getFluidState(pos); ++ // CraftBukkit end + if (!fluidState.is(FluidTags.WATER)) { + return BlockPos.TraversalNodeStatus.SKIP; +- } else if (state.getBlock() instanceof BucketPickup bucketPickup && !bucketPickup.pickupBlock(null, level, pos, state).isEmpty()) { ++ } else if (blockState.getBlock() instanceof BucketPickup bucketPickup ++ && !bucketPickup.pickupBlock(null, blockList, pos, blockState).isEmpty()) { // CraftBukkit + return BlockPos.TraversalNodeStatus.ACCEPT; + } else { +- if (state.getBlock() instanceof LiquidBlock) { +- level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); ++ if (blockState.getBlock() instanceof LiquidBlock) { ++ blockList.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit } else { -- BlockState blockState = level.getBlockState(blockPos); -- FluidState fluidState = level.getFluidState(blockPos); -+ // CraftBukkit start -+ BlockState blockState = blockList.getBlockState(blockPos); -+ FluidState fluidState = blockList.getFluidState(blockPos); -+ // CraftBukkit end - if (!fluidState.is(FluidTags.WATER)) { +- if (!state.is(Blocks.KELP) && !state.is(Blocks.KELP_PLANT) && !state.is(Blocks.SEAGRASS) && !state.is(Blocks.TALL_SEAGRASS)) { ++ if (!blockState.is(Blocks.KELP) && !blockState.is(Blocks.KELP_PLANT) && !blockState.is(Blocks.SEAGRASS) && !blockState.is(Blocks.TALL_SEAGRASS)) { return BlockPos.TraversalNodeStatus.SKIP; - } else if (blockState.getBlock() instanceof BucketPickup bucketPickup -- && !bucketPickup.pickupBlock(null, level, blockPos, blockState).isEmpty()) { -+ && !bucketPickup.pickupBlock(null, blockList, blockPos, blockState).isEmpty()) { // CraftBukkit - return BlockPos.TraversalNodeStatus.ACCEPT; - } else { - if (blockState.getBlock() instanceof LiquidBlock) { -- level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); -+ blockList.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit - } else { - if (!blockState.is(Blocks.KELP) - && !blockState.is(Blocks.KELP_PLANT) -@@ -81,16 +_,49 @@ - return BlockPos.TraversalNodeStatus.SKIP; - } - -- BlockEntity blockEntity = blockState.hasBlockEntity() ? level.getBlockEntity(blockPos) : null; -- dropResources(blockState, level, blockPos, blockEntity); -- level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); -+ // CraftBukkit start -+ // BlockEntity blockEntity = blockState.hasBlockEntity() ? level.getBlockEntity(blockPos) : null; -+ // dropResources(blockState, level, blockPos, blockEntity); -+ blockList.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); -+ // CraftBukkit end - } - - return BlockPos.TraversalNodeStatus.ACCEPT; } + +- BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; +- dropResources(state, level, pos, blockEntity); +- level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); ++ // CraftBukkit start ++ // BlockEntity blockEntity = blockState.hasBlockEntity() ? level.getBlockEntity(pos) : null; ++ // dropResources(blockState, level, pos, blockEntity); ++ blockList.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); ++ // CraftBukkit end } + + return BlockPos.TraversalNodeStatus.ACCEPT; } -- ) -- > 1; -+ ); + } +- }) > 1; ++ }); + // CraftBukkit start + java.util.List snapshots = blockList.getSnapshotBlocks(); // Is a clone + if (!snapshots.isEmpty()) { -+ final org.bukkit.block.Block sponge = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ final org.bukkit.block.Block sponge = org.bukkit.craftbukkit.block.CraftBlock.at(level, startPos); + + org.bukkit.event.block.SpongeAbsorbEvent event = new org.bukkit.event.block.SpongeAbsorbEvent(sponge, (java.util.List) (java.util.List) snapshots); + if (!event.callEvent()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch new file mode 100644 index 000000000000..1390b4a5cede --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/world/level/block/SpreadingSnowyBlock.java ++++ b/net/minecraft/world/level/block/SpreadingSnowyBlock.java +@@ -46,10 +_,16 @@ + + @Override + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { ++ if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks + Registry blocks = level.registryAccess().lookupOrThrow(Registries.BLOCK); + Optional baseBlock = blocks.getOptional(this.baseBlock); + if (!baseBlock.isEmpty()) { + if (!canStayAlive(state, level, pos)) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, baseBlock.get().defaultBlockState()).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + level.setBlockAndUpdate(pos, baseBlock.get().defaultBlockState()); + } else { + if (level.getMaxLocalRawBrightness(pos.above()) >= 9) { +@@ -58,7 +_,7 @@ + for (int i = 0; i < 4; i++) { + BlockPos testPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); + if (level.getBlockState(testPos).is(baseBlock.get()) && canPropagate(defaultBlockState, level, testPos)) { +- level.setBlockAndUpdate(testPos, defaultBlockState.setValue(SNOWY, isSnowySetting(level.getBlockState(testPos.above())))); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, testPos, defaultBlockState.setValue(SNOWY, isSnowySetting(level.getBlockState(testPos.above()))), Block.UPDATE_ALL); // CraftBukkit + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java.patch deleted file mode 100644 index 21f0f33a6996..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -+++ b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -@@ -39,7 +_,13 @@ - - @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { -+ if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks - if (!canBeGrass(state, level, pos)) { -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) { -+ return; -+ } -+ // CraftBukkit end - level.setBlockAndUpdate(pos, Blocks.DIRT.defaultBlockState()); - } else { - if (level.getMaxLocalRawBrightness(pos.above()) >= 9) { -@@ -48,7 +_,7 @@ - for (int i = 0; i < 4; i++) { - BlockPos blockPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); - if (level.getBlockState(blockPos).is(Blocks.DIRT) && canPropagate(blockState, level, blockPos)) { -- level.setBlockAndUpdate(blockPos, blockState.setValue(SNOWY, isSnowySetting(level.getBlockState(blockPos.above())))); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState.setValue(SNOWY, isSnowySetting(level.getBlockState(blockPos.above()))), Block.UPDATE_ALL); // CraftBukkit - } - } - } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/StemBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/StemBlock.java.patch index 6649f03cd094..f7aa1c9776a8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/StemBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/StemBlock.java.patch @@ -1,38 +1,38 @@ --- a/net/minecraft/world/level/block/StemBlock.java +++ b/net/minecraft/world/level/block/StemBlock.java -@@ -70,11 +_,11 @@ - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { +@@ -83,11 +_,11 @@ + protected void randomTick(BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (level.getRawBrightness(pos, 0) >= 9) { float growthSpeed = CropBlock.getGrowthSpeed(this, level, pos); - if (random.nextInt((int)(25.0F / growthSpeed) + 1) == 0) { + if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? level.spigotConfig.pumpkinModifier : level.spigotConfig.melonModifier) / (100.0F * (Math.floor((25.0F / growthSpeed) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution - int ageValue = state.getValue(AGE); - if (ageValue < 7) { - state = state.setValue(AGE, ageValue + 1); + int age = state.getValue(AGE); + if (age < 7) { + state = state.setValue(AGE, age + 1); - level.setBlock(pos, state, Block.UPDATE_CLIENTS); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state, Block.UPDATE_CLIENTS); // CraftBukkit } else { - Direction randomDirection = Direction.Plane.HORIZONTAL.getRandomDirection(random); - BlockPos blockPos = pos.relative(randomDirection); -@@ -84,7 +_,11 @@ - Optional optional = registry.getOptional(this.fruit); - Optional optional1 = registry.getOptional(this.attachedStem); - if (optional.isPresent() && optional1.isPresent()) { -- level.setBlockAndUpdate(blockPos, optional.get().defaultBlockState()); + Direction direction = Direction.Plane.HORIZONTAL.getRandomDirection(random); + BlockPos relative = pos.relative(direction); +@@ -97,7 +_,11 @@ + Optional fruit = blocks.getOptional(this.fruit); + Optional stem = blocks.getOptional(this.attachedStem); + if (fruit.isPresent() && stem.isPresent()) { +- level.setBlockAndUpdate(relative, fruit.get().defaultBlockState()); + // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockPos, optional.get().defaultBlockState(), Block.UPDATE_ALL)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, relative, fruit.get().defaultBlockState(), Block.UPDATE_ALL)) { + return; + } + // CraftBukkit end - level.setBlockAndUpdate(pos, optional1.get().defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, randomDirection)); + level.setBlockAndUpdate(pos, stem.get().defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, direction)); } } -@@ -112,7 +_,7 @@ - public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { - int min = Math.min(7, state.getValue(AGE) + Mth.nextInt(level.random, 2, 5)); - BlockState blockState = state.setValue(AGE, min); -- level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, blockState, Block.UPDATE_CLIENTS); // CraftBukkit - if (min == 7) { - blockState.randomTick(level, pos, level.random); +@@ -125,7 +_,7 @@ + public void performBonemeal(final ServerLevel level, final RandomSource random, final BlockPos pos, final BlockState state) { + int age = Math.min(7, state.getValue(AGE) + Mth.nextInt(random, 2, 5)); + BlockState newState = state.setValue(AGE, age); +- level.setBlock(pos, newState, Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, newState, Block.UPDATE_CLIENTS); // CraftBukkit + if (age == 7) { + newState.randomTick(level, pos, random); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch index f8283db868a2..3d21aeed59fb 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch @@ -1,8 +1,8 @@ --- a/net/minecraft/world/level/block/StonecutterBlock.java +++ b/net/minecraft/world/level/block/StonecutterBlock.java -@@ -48,8 +_,9 @@ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -50,8 +_,9 @@ + final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult + ) { if (!level.isClientSide()) { - player.openMenu(state.getMenuProvider(level, pos)); + if (player.openMenu(state.getMenuProvider(level, pos)).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch index 8fff3fd247e1..128b8087e3d5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/block/SugarCaneBlock.java +++ b/net/minecraft/world/level/block/SugarCaneBlock.java @@ -55,12 +_,13 @@ - i++; + height++; } -- if (i < 3) { -+ if (i < level.paperConfig().maxGrowthHeight.reeds) { // Paper - Configurable cactus/bamboo/reed growth height - int ageValue = state.getValue(AGE); -- if (ageValue == 15) { +- if (height < 3) { ++ if (height < level.paperConfig().maxGrowthHeight.reeds) { // Paper - Configurable cactus/bamboo/reed growth height + int age = state.getValue(AGE); +- if (age == 15) { - level.setBlockAndUpdate(pos.above(), this.defaultBlockState()); + int modifier = level.spigotConfig.caneModifier; // Spigot - SPIGOT-7159: Better modifier resolution -+ if (ageValue >= 15 || (modifier != 100 && random.nextFloat() < (modifier / (100.0F * 16)))) { // Spigot - SPIGOT-7159: Better modifier resolution ++ if (age >= 15 || (modifier != 100 && random.nextFloat() < (modifier / (100.0F * 16)))) { // Spigot - SPIGOT-7159: Better modifier resolution + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos.above(), this.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit level.setBlock(pos, state.setValue(AGE, 0), Block.UPDATE_NONE); - } else { + } else if (modifier == 100 || random.nextFloat() < (modifier / (100.0F * 16))) { // Spigot - SPIGOT-7159: Better modifier resolution - level.setBlock(pos, state.setValue(AGE, ageValue + 1), Block.UPDATE_NONE); + level.setBlock(pos, state.setValue(AGE, age + 1), Block.UPDATE_NONE); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch index 80ea0cecb365..ff448a23dfea 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch @@ -1,47 +1,48 @@ --- a/net/minecraft/world/level/block/SweetBerryBushBlock.java +++ b/net/minecraft/world/level/block/SweetBerryBushBlock.java -@@ -71,15 +_,16 @@ +@@ -71,9 +_,9 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - int ageValue = state.getValue(AGE); -- if (ageValue < 3 && random.nextInt(5) == 0 && level.getRawBrightness(pos.above(), 0) >= 9) { -+ if (ageValue < 3 && random.nextFloat() < (level.spigotConfig.sweetBerryModifier / (100.0F * 5)) && level.getRawBrightness(pos.above(), 0) >= 9) { // Spigot - SPIGOT-7159: Better modifier resolution - BlockState blockState = state.setValue(AGE, ageValue + 1); -- level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, blockState, Block.UPDATE_CLIENTS)) return; // CraftBukkit - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + int age = state.getValue(AGE); +- if (age < 3 && random.nextInt(5) == 0 && level.getRawBrightness(pos.above(), 0) >= 9) { ++ if (age < 3 && random.nextFloat() < (level.spigotConfig.sweetBerryModifier / (100.0F * 5)) && level.getRawBrightness(pos.above(), 0) >= 9) { // Spigot - SPIGOT-7159: Better modifier resolution + BlockState newState = state.setValue(AGE, age + 1); +- level.setBlock(pos, newState, Block.UPDATE_CLIENTS); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, newState, Block.UPDATE_CLIENTS)) return; // CraftBukkit + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(newState)); } } - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -87,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity instanceof LivingEntity && entity.getType() != EntityType.FOX && entity.getType() != EntityType.BEE) { + if (entity instanceof LivingEntity && !entity.is(EntityType.FOX) && !entity.is(EntityType.BEE)) { entity.makeStuckInBlock(state, new Vec3(0.8F, 0.75, 0.8F)); if (level instanceof ServerLevel serverLevel && state.getValue(AGE) != 0) { -@@ -88,7 +_,7 @@ - double abs = Math.abs(vec3.x()); - double abs1 = Math.abs(vec3.z()); - if (abs >= 0.003F || abs1 >= 0.003F) { +@@ -95,7 +_,7 @@ + double xs = Math.abs(movement.x()); + double zs = Math.abs(movement.z()); + if (xs >= 0.003F || zs >= 0.003F) { - entity.hurtServer(serverLevel, level.damageSources().sweetBerryBush(), 1.0F); + entity.hurtServer(serverLevel, level.damageSources().sweetBerryBush().eventBlockDamager(level, pos), 1.0F); // CraftBukkit } } } -@@ -110,6 +_,7 @@ - protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { +@@ -125,6 +_,7 @@ + ) { if (state.getValue(AGE) > 1) { if (level instanceof ServerLevel serverLevel) { + java.util.List drops = new java.util.ArrayList<>(); // Paper Block.dropFromBlockInteractLootTable( serverLevel, BuiltInLootTables.HARVEST_SWEET_BERRY_BUSH, -@@ -117,8 +_,17 @@ +@@ -132,8 +_,17 @@ level.getBlockEntity(pos), null, player, -- (serverLevel1, itemStack) -> Block.popResource(serverLevel1, pos, itemStack) -+ (serverLevel1, itemStack) -> drops.add(itemStack) // Paper +- (serverlvl, itemStack) -> Block.popResource(serverlvl, pos, itemStack) ++ (serverlvl, itemStack) -> drops.add(itemStack) // Paper ); + // CraftBukkit start - useWithoutItem is always MAIN_HAND + org.bukkit.event.player.PlayerHarvestBlockEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerHarvestBlockEvent(level, pos, player, InteractionHand.MAIN_HAND, drops); @@ -53,5 +54,5 @@ + } + // CraftBukkit end serverLevel.playSound( - null, pos, SoundEvents.SWEET_BERRY_BUSH_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, 0.8F + serverLevel.random.nextFloat() * 0.4F + null, pos, SoundEvents.SWEET_BERRY_BUSH_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, 0.8F + serverLevel.getRandom().nextFloat() * 0.4F ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TargetBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TargetBlock.java.patch index 6ea06255f252..bc05106f9b51 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TargetBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TargetBlock.java.patch @@ -2,25 +2,25 @@ +++ b/net/minecraft/world/level/block/TargetBlock.java @@ -42,6 +_,10 @@ @Override - protected void onProjectileHit(Level level, BlockState state, BlockHitResult hit, Projectile projectile) { - int i = updateRedstoneOutput(level, state, hit, projectile); + protected void onProjectileHit(final Level level, final BlockState state, final BlockHitResult hitResult, final Projectile projectile) { + int outputStrength = updateRedstoneOutput(level, state, hitResult, projectile); + // Paper start - Add TargetHitEvent + } -+ private static void awardTargetHitCriteria(Projectile projectile, BlockHitResult hit, int i) { ++ private static void awardTargetHitCriteria(Projectile projectile, BlockHitResult hitResult, int outputStrength) { + // Paper end - Add TargetHitEvent - if (projectile.getOwner() instanceof ServerPlayer serverPlayer) { - serverPlayer.awardStat(Stats.TARGET_HIT); - CriteriaTriggers.TARGET_BLOCK_HIT.trigger(serverPlayer, projectile, hit.getLocation(), i); + if (projectile.getOwner() instanceof ServerPlayer playerOwner) { + playerOwner.awardStat(Stats.TARGET_HIT); + CriteriaTriggers.TARGET_BLOCK_HIT.trigger(playerOwner, projectile, hitResult.getLocation(), outputStrength); @@ -51,9 +_,29 @@ - private static int updateRedstoneOutput(LevelAccessor level, BlockState state, BlockHitResult hit, Entity projectile) { - int redstoneStrength = getRedstoneStrength(hit, hit.getLocation()); - int i = projectile instanceof AbstractArrow ? 20 : 8; + private static int updateRedstoneOutput(final LevelAccessor level, final BlockState state, final BlockHitResult hitResult, final Entity entity) { + int redstoneStrength = getRedstoneStrength(hitResult, hitResult.getLocation()); + int duration = entity instanceof AbstractArrow ? 20 : 8; + // Paper start - Add TargetHitEvent + boolean shouldAward = false; -+ if (projectile instanceof Projectile) { -+ final org.bukkit.craftbukkit.block.CraftBlock craftBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, hit.getBlockPos()); -+ final org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(hit.getDirection()); -+ final io.papermc.paper.event.block.TargetHitEvent targetHitEvent = new io.papermc.paper.event.block.TargetHitEvent((org.bukkit.entity.Projectile) projectile.getBukkitEntity(), craftBlock, blockFace, redstoneStrength); ++ if (entity instanceof Projectile) { ++ final org.bukkit.craftbukkit.block.CraftBlock craftBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, hitResult.getBlockPos()); ++ final org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(hitResult.getDirection()); ++ final io.papermc.paper.event.block.TargetHitEvent targetHitEvent = new io.papermc.paper.event.block.TargetHitEvent((org.bukkit.entity.Projectile) entity.getBukkitEntity(), craftBlock, blockFace, redstoneStrength); + if (targetHitEvent.callEvent()) { + redstoneStrength = targetHitEvent.getSignalStrength(); + shouldAward = true; @@ -29,13 +29,13 @@ + } + } + // Paper end - Add TargetHitEvent - if (!level.getBlockTicks().hasScheduledTick(hit.getBlockPos(), state.getBlock())) { - setOutputPower(level, state, redstoneStrength, hit.getBlockPos(), i); + if (!level.getBlockTicks().hasScheduledTick(hitResult.getBlockPos(), state.getBlock())) { + setOutputPower(level, state, redstoneStrength, hitResult.getBlockPos(), duration); } + + // Paper start - Award Hit Criteria after Block Update + if (shouldAward) { -+ awardTargetHitCriteria((Projectile) projectile, hit, redstoneStrength); ++ awardTargetHitCriteria((Projectile) entity, hitResult, redstoneStrength); + } + // Paper end - Award Hit Criteria after Block Update diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch index 478b2ae1b110..a2dbd1b38a0a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch @@ -2,66 +2,66 @@ +++ b/net/minecraft/world/level/block/TntBlock.java @@ -47,7 +_,7 @@ @Override - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { if (!oldState.is(state.getBlock())) { - if (level.hasNeighborSignal(pos) && prime(level, pos)) { + if (level.hasNeighborSignal(pos) && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent level.removeBlock(pos, false); } } -@@ -55,7 +_,7 @@ - - @Override - protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +@@ -57,7 +_,7 @@ + protected void neighborChanged( + final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston + ) { - if (level.hasNeighborSignal(pos) && prime(level, pos)) { + if (level.hasNeighborSignal(pos) && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent level.removeBlock(pos, false); } } -@@ -63,7 +_,7 @@ +@@ -65,7 +_,7 @@ @Override - public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) { + public BlockState playerWillDestroy(final Level level, final BlockPos pos, final BlockState state, final Player player) { if (!level.isClientSide() && !player.getAbilities().instabuild && state.getValue(UNSTABLE)) { - prime(level, pos); + prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.BLOCK_BREAK, player, null)); // CraftBukkit - TNTPrimeEvent } return super.playerWillDestroy(level, pos, state, player); -@@ -80,11 +_,16 @@ +@@ -82,11 +_,16 @@ } - public static boolean prime(Level level, BlockPos pos) { + public static boolean prime(final Level level, final BlockPos pos) { - return prime(level, pos, null); + // Paper start + return prime(level, pos, null, () -> true); + } -+ public static boolean prime(Level level, BlockPos pos, java.util.function.BooleanSupplier event) { ++ public static boolean prime(final Level level, final BlockPos pos, final java.util.function.BooleanSupplier event) { + return prime(level, pos, null, event); + // Paper end } -- private static boolean prime(Level level, BlockPos pos, @Nullable LivingEntity entity) { +- private static boolean prime(final Level level, final BlockPos pos, final @Nullable LivingEntity source) { - if (level instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.TNT_EXPLODES)) { -+ private static boolean prime(Level level, BlockPos pos, @Nullable LivingEntity entity, java.util.function.BooleanSupplier event) { // Paper ++ private static boolean prime(final Level level, final BlockPos pos, final @Nullable LivingEntity source, final java.util.function.BooleanSupplier event) { // Paper + if (level instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.TNT_EXPLODES) && event.getAsBoolean()) { // Paper - PrimedTnt primedTnt = new PrimedTnt(level, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, entity); - level.addFreshEntity(primedTnt); - level.playSound(null, primedTnt.getX(), primedTnt.getY(), primedTnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); -@@ -102,7 +_,7 @@ - if (!stack.is(Items.FLINT_AND_STEEL) && !stack.is(Items.FIRE_CHARGE)) { - return super.useItemOn(stack, state, level, pos, player, hand, hitResult); + PrimedTnt tnt = new PrimedTnt(level, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, source); + level.addFreshEntity(tnt); + level.playSound(null, tnt.getX(), tnt.getY(), tnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); +@@ -110,7 +_,7 @@ + if (!itemStack.is(Items.FLINT_AND_STEEL) && !itemStack.is(Items.FIRE_CHARGE)) { + return super.useItemOn(itemStack, state, level, pos, player, hand, hitResult); } else { - if (prime(level, pos, player)) { + if (prime(level, pos, player, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.PLAYER, player, null))) { // Paper level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL_IMMEDIATE); - Item item = stack.getItem(); - if (stack.is(Items.FLINT_AND_STEEL)) { -@@ -128,7 +_,7 @@ + Item item = itemStack.getItem(); + if (itemStack.is(Items.FLINT_AND_STEEL)) { +@@ -136,7 +_,7 @@ Entity owner = projectile.getOwner(); if (projectile.isOnFire() - && projectile.mayInteract(serverLevel, blockPos) -- && prime(level, blockPos, owner instanceof LivingEntity ? (LivingEntity)owner : null)) { -+ && prime(level, blockPos, owner instanceof LivingEntity ? (LivingEntity)owner : null, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockPos, state.getFluidState().createLegacyBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.PROJECTILE, projectile, null))) { // Paper - level.removeBlock(blockPos, false); + && projectile.mayInteract(serverLevel, pos) +- && prime(level, pos, owner instanceof LivingEntity ? (LivingEntity)owner : null)) { ++ && prime(level, pos, owner instanceof LivingEntity ? (LivingEntity)owner : null, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, pos, state.getFluidState().createLegacyBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.PROJECTILE, projectile, null))) { // Paper + level.removeBlock(pos, false); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TrapDoorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TrapDoorBlock.java.patch index 81c5d46478c4..7d266526bbb6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TrapDoorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TrapDoorBlock.java.patch @@ -1,26 +1,26 @@ --- a/net/minecraft/world/level/block/TrapDoorBlock.java +++ b/net/minecraft/world/level/block/TrapDoorBlock.java -@@ -128,7 +_,37 @@ +@@ -133,7 +_,37 @@ if (!level.isClientSide()) { - boolean hasNeighborSignal = level.hasNeighborSignal(pos); - if (hasNeighborSignal != state.getValue(POWERED)) { -- if (state.getValue(OPEN) != hasNeighborSignal) { + boolean signal = level.hasNeighborSignal(pos); + if (signal != state.getValue(POWERED)) { +- if (state.getValue(OPEN) != signal) { + // CraftBukkit start + org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + int power = bblock.getBlockPower(); + int oldPower = state.getValue(TrapDoorBlock.OPEN) ? 15 : 0; + -+ if (oldPower == 0 ^ power == 0 || neighborBlock.defaultBlockState().isSignalSource()) { ++ if (oldPower == 0 ^ power == 0 || block.defaultBlockState().isSignalSource()) { + org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bblock, oldPower, power); + level.getCraftServer().getPluginManager().callEvent(eventRedstone); -+ hasNeighborSignal = eventRedstone.getNewCurrent() > 0; ++ signal = eventRedstone.getNewCurrent() > 0; + } + // CraftBukkit end + // Paper start - break redstone on trapdoors early -+ boolean open = state.getValue(TrapDoorBlock.OPEN) != hasNeighborSignal; ++ boolean open = state.getValue(TrapDoorBlock.OPEN) != signal; + // note: this must run before any state for this block/its neighbours are written to the world + // we allow the redstone event to fire so that plugins can block -+ if (hasNeighborSignal && open) { // if we are now powered and it caused the trap door to open ++ if (signal && open) { // if we are now powered and it caused the trap door to open + // in this case, first check for the redstone on top first + BlockPos abovePos = pos.above(); + BlockState above = level.getBlockState(abovePos); @@ -36,6 +36,6 @@ + } + if (open) { + // Paper end - break redstone on trapdoors early - state = state.setValue(OPEN, hasNeighborSignal); - this.playSound(null, level, pos, hasNeighborSignal); + state = state.setValue(OPEN, signal); + this.playSound(null, level, pos, signal); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireBlock.java.patch index 3b60250e8717..56e3ed1b8398 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireBlock.java.patch @@ -1,77 +1,77 @@ --- a/net/minecraft/world/level/block/TripWireBlock.java +++ b/net/minecraft/world/level/block/TripWireBlock.java -@@ -73,6 +_,7 @@ +@@ -72,6 +_,7 @@ @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { + public BlockState getStateForPlacement(final BlockPlaceContext context) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return this.defaultBlockState(); // Paper - place tripwire without updating BlockGetter level = context.getLevel(); - BlockPos clickedPos = context.getClickedPos(); + BlockPos pos = context.getClickedPos(); return this.defaultBlockState() -@@ -93,6 +_,7 @@ - BlockState neighborState, - RandomSource random +@@ -92,6 +_,7 @@ + final BlockState neighbourState, + final RandomSource random ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent tripwire from updating - return direction.getAxis().isHorizontal() - ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), this.shouldConnectTo(neighborState, direction)) - : super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); -@@ -100,6 +_,7 @@ + return directionToNeighbour.getAxis().isHorizontal() + ? state.setValue(PROPERTY_BY_DIRECTION.get(directionToNeighbour), this.shouldConnectTo(neighbourState, directionToNeighbour)) + : super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); +@@ -99,6 +_,7 @@ @Override - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating if (!oldState.is(state.getBlock())) { this.updateSource(level, pos, state); } -@@ -107,6 +_,7 @@ +@@ -106,6 +_,7 @@ @Override - protected void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) { + protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating if (!movedByPiston) { this.updateSource(level, pos, state.setValue(POWERED, true)); } -@@ -114,6 +_,7 @@ +@@ -113,6 +_,7 @@ @Override - public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) { + public BlockState playerWillDestroy(final Level level, final BlockPos pos, final BlockState state, final Player player) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent disarming tripwires if (!level.isClientSide() && !player.getMainHandItem().isEmpty() && player.getMainHandItem().is(Items.SHEARS)) { level.setBlock(pos, state.setValue(DISARMED, true), Block.UPDATE_NONE); level.gameEvent(player, GameEvent.SHEAR, pos); -@@ -123,6 +_,7 @@ +@@ -122,6 +_,7 @@ } - private void updateSource(Level level, BlockPos pos, BlockState state) { + private void updateSource(final Level level, final BlockPos pos, final BlockState state) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating for (Direction direction : new Direction[]{Direction.SOUTH, Direction.WEST}) { for (int i = 1; i < 42; i++) { - BlockPos blockPos = pos.relative(direction, i); -@@ -148,6 +_,8 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { + BlockPos testPos = pos.relative(direction, i); +@@ -154,6 +_,8 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwires from detecting collision + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (!level.isClientSide()) { if (!state.getValue(POWERED)) { this.checkPressed(level, pos, List.of(entity)); -@@ -157,6 +_,7 @@ +@@ -163,6 +_,7 @@ @Override - protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwire pressed check if (level.getBlockState(pos).getValue(POWERED)) { this.checkPressed(level, pos); } -@@ -180,6 +_,39 @@ +@@ -186,6 +_,39 @@ } } } + + // CraftBukkit start - Call interact even when triggering connected tripwire -+ if (poweredValue != flag && flag && blockState.getValue(TripWireBlock.ATTACHED)) { ++ if (wasPressed != shouldBePressed && shouldBePressed && state.getValue(TripWireBlock.ATTACHED)) { + org.bukkit.plugin.PluginManager manager = level.getCraftServer().getPluginManager(); + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + boolean allowed = false; @@ -103,5 +103,5 @@ + } + // CraftBukkit end - if (flag != poweredValue) { - blockState = blockState.setValue(POWERED, flag); + if (shouldBePressed != wasPressed) { + state = state.setValue(POWERED, shouldBePressed); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch index 426cec4007c3..2959948ed5af 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch @@ -1,31 +1,30 @@ --- a/net/minecraft/world/level/block/TripWireHookBlock.java +++ b/net/minecraft/world/level/block/TripWireHookBlock.java -@@ -112,10 +_,10 @@ - if (optionalValue.isPresent()) { - Direction direction = optionalValue.get(); - boolean flag = hookState.getOptionalValue(ATTACHED).orElse(false); -- boolean flag1 = hookState.getOptionalValue(POWERED).orElse(false); -+ boolean flag1 = hookState.getOptionalValue(POWERED).orElse(false); // Paper - diff on change, for event below - Block block = hookState.getBlock(); - boolean flag2 = !attaching; -- boolean flag3 = false; -+ boolean flag3 = false; // Paper - diff on change, for event below - int i = 0; - BlockState[] blockStates = new BlockState[42]; +@@ -118,10 +_,10 @@ + if (facingOptional.isPresent()) { + Direction direction = facingOptional.get(); + boolean wasAttached = state.getOptionalValue(ATTACHED).orElse(false); +- boolean wasPowered = state.getOptionalValue(POWERED).orElse(false); ++ boolean wasPowered = state.getOptionalValue(POWERED).orElse(false); // Paper - diff on change, for event below + Block block = state.getBlock(); + boolean attached = !isBeingDestroyed; +- boolean powered = false; ++ boolean powered = false; // Paper - diff on change, for event below + int receiverPos = 0; + BlockState[] wireStates = new BlockState[42]; -@@ -151,21 +_,48 @@ - flag2 &= i > 1; - flag3 &= flag2; - BlockState blockState1 = block.defaultBlockState().trySetValue(ATTACHED, flag2).trySetValue(POWERED, flag3); +@@ -157,8 +_,20 @@ + attached &= receiverPos > 1; + powered &= attached; + BlockState newState = block.defaultBlockState().trySetValue(ATTACHED, attached).trySetValue(POWERED, powered); + boolean cancelledEmitterHook = false, cancelledReceiverHook = false; // Paper - Call BlockRedstoneEvent -+ boolean wasPowered = flag1, willBePowered = flag3; // Paper - OBFHELPER - if (i > 0) { - BlockPos blockPosx = pos.relative(direction, i); + if (receiverPos > 0) { + BlockPos testPosx = pos.relative(direction, receiverPos); + // Paper start - Call BlockRedstoneEvent -+ if (wasPowered != willBePowered) { -+ int newCurrent = willBePowered ? 15 : 0; ++ if (wasPowered != powered) { ++ int newCurrent = powered ? 15 : 0; + org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPosx), wasPowered ? 15 : 0, newCurrent ++ org.bukkit.craftbukkit.block.CraftBlock.at(level, testPosx), wasPowered ? 15 : 0, newCurrent + ); + event.callEvent(); + cancelledReceiverHook = event.getNewCurrent() != newCurrent; @@ -33,15 +32,18 @@ + if (!cancelledReceiverHook) { // always trigger two events even when the first hook current change is cancelled + // Paper end - Call BlockRedstoneEvent Direction opposite = direction.getOpposite(); - level.setBlock(blockPosx, blockState1.setValue(FACING, opposite), Block.UPDATE_ALL); - notifyNeighbors(block, level, blockPosx, opposite); - emitState(level, blockPosx, flag2, flag3, flag, flag1); + level.setBlock(testPosx, newState.setValue(FACING, opposite), Block.UPDATE_ALL); + notifyNeighbors(block, level, testPosx, opposite); +@@ -168,15 +_,29 @@ + } + + emitState(level, testPosx, attached, powered, wasAttached, wasPowered); - } + } // Paper - Call BlockRedstoneEvent + } + // Paper start - Call BlockRedstoneEvent -+ if (wasPowered != willBePowered) { -+ int newCurrent = willBePowered ? 15 : 0; ++ if (wasPowered != powered) { ++ int newCurrent = powered ? 15 : 0; + org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), wasPowered ? 15 : 0, newCurrent + ); @@ -51,24 +53,24 @@ + // Paper end - Call BlockRedstoneEvent + if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent - emitState(level, pos, flag2, flag3, flag, flag1); - if (!attaching) { + emitState(level, pos, attached, powered, wasAttached, wasPowered); + if (!isBeingDestroyed) { + if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update - level.setBlock(pos, blockState1.setValue(FACING, direction), Block.UPDATE_ALL); - if (shouldNotifyNeighbours) { + level.setBlock(pos, newState.setValue(FACING, direction), Block.UPDATE_ALL); + if (canUpdate) { notifyNeighbors(block, level, pos, direction); } } + } // Paper - Call BlockRedstoneEvent - if (flag != flag2) { - for (int i2 = 1; i2 < i; i2++) { -@@ -174,7 +_,7 @@ - if (blockState2 != null) { - BlockState blockState3 = level.getBlockState(blockPos1); - if (blockState3.is(Blocks.TRIPWIRE) || blockState3.is(Blocks.TRIPWIRE_HOOK)) { -- level.setBlock(blockPos1, blockState2.trySetValue(ATTACHED, flag2), Block.UPDATE_ALL); -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !blockState3.is(Blocks.TRIPWIRE)) level.setBlock(blockPos1, blockState2.trySetValue(ATTACHED, flag2), Block.UPDATE_ALL); // Paper - prevent tripwire from updating + if (wasAttached != attached) { + for (int i = 1; i < receiverPos; i++) { +@@ -185,7 +_,7 @@ + if (wireData != null) { + BlockState testPosState = level.getBlockState(testPosx); + if (testPosState.is(Blocks.TRIPWIRE) || testPosState.is(Blocks.TRIPWIRE_HOOK)) { +- level.setBlock(testPosx, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !testPosState.is(Blocks.TRIPWIRE)) level.setBlock(testPosx, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); // Paper - prevent tripwire from updating } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch index 88d48aac5312..49ba7862869d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch @@ -3,7 +3,7 @@ @@ -75,6 +_,19 @@ && level instanceof ServerLevel serverLevel && this.canDestroyEgg(serverLevel, entity) - && level.random.nextInt(chance) == 0) { + && level.getRandom().nextInt(randomness) == 0) { + // CraftBukkit start - Step on eggs + org.bukkit.event.Cancellable cancellable; + if (entity instanceof Player) { @@ -22,15 +22,15 @@ } @@ -96,10 +_,19 @@ if (this.shouldUpdateHatchLevel(level, pos) && onSand(level, pos)) { - int hatchValue = state.getValue(HATCH); - if (hatchValue < 2) { + int hatch = state.getValue(HATCH); + if (hatch < 2) { + // CraftBukkit start - Call BlockGrowEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(HATCH, hatchValue + 1), Block.UPDATE_CLIENTS)) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(HATCH, hatch + 1), Block.UPDATE_CLIENTS)) { + return; + } + // CraftBukkit end level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F); -- level.setBlock(pos, state.setValue(HATCH, hatchValue + 1), Block.UPDATE_CLIENTS); +- level.setBlock(pos, state.setValue(HATCH, hatch + 1), Block.UPDATE_CLIENTS); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); } else { + // CraftBukkit start - Call BlockFadeEvent @@ -50,14 +50,14 @@ } } } -@@ -139,8 +_,8 @@ - } - - @Override -- public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) { -- super.playerDestroy(level, player, pos, state, blockEntity, stack); -+ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { // Paper - fix drops not preventing stats/food exhaustion -+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion +@@ -146,8 +_,9 @@ + final BlockState state, + final @Nullable BlockEntity blockEntity, + final ItemStack destroyedWith ++ , boolean includeDrops, boolean dropExp // Paper - fix drops not preventing stats/food exhaustion + ) { +- super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith); ++ super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith, includeDrops, dropExp); // Paper - fix drops not preventing stats/food exhaustion this.decreaseEggs(level, pos, state); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/VegetationBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/VegetationBlock.java.patch index cc5f85a5a349..c15b56a485d2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/VegetationBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/VegetationBlock.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/block/VegetationBlock.java +++ b/net/minecraft/world/level/block/VegetationBlock.java @@ -35,9 +_,15 @@ - BlockState neighborState, - RandomSource random + final BlockState neighbourState, + final RandomSource random ) { - return !state.canSurvive(level, pos) - ? Blocks.AIR.defaultBlockState() -- : super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); +- : super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + // CraftBukkit start + if (!state.canSurvive(level, pos)) { + // Suppress during worldgen @@ -14,7 +14,7 @@ + return Blocks.AIR.defaultBlockState(); + } + } -+ return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); ++ return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch index 653121c288a3..104fc06cc92d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch @@ -2,67 +2,69 @@ +++ b/net/minecraft/world/level/block/VineBlock.java @@ -166,7 +_,7 @@ @Override - protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (level.getGameRules().get(GameRules.SPREAD_VINES)) { - if (random.nextInt(4) == 0) { + if (random.nextFloat() < (level.spigotConfig.vineModifier / (100.0F * 4))) { // Spigot - SPIGOT-7159: Better modifier resolution - Direction random1 = Direction.getRandom(random); - BlockPos blockPos = pos.above(); - if (random1.getAxis().isHorizontal() && !state.getValue(getPropertyForFace(random1))) { -@@ -180,28 +_,31 @@ - boolean value1 = state.getValue(getPropertyForFace(counterClockWise)); - BlockPos blockPos2 = blockPos1.relative(clockWise); - BlockPos blockPos3 = blockPos1.relative(counterClockWise); + Direction testDirection = Direction.getRandom(random); + BlockPos abovePos = pos.above(); + if (testDirection.getAxis().isHorizontal() && !state.getValue(getPropertyForFace(testDirection))) { +@@ -180,30 +_,33 @@ + boolean ccwHasConnectingFace = state.getValue(getPropertyForFace(ccwDirection)); + BlockPos cwTestPos = testPos.relative(cwDirection); + BlockPos ccwTestPos = testPos.relative(ccwDirection); + // CraftBukkit start - Call BlockSpreadEvent + BlockPos source = pos; - if (value && isAcceptableNeighbour(level, blockPos2, clockWise)) { -- level.setBlock(blockPos1, this.defaultBlockState().setValue(getPropertyForFace(clockWise), true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(getPropertyForFace(clockWise), true), Block.UPDATE_CLIENTS); - } else if (value1 && isAcceptableNeighbour(level, blockPos3, counterClockWise)) { -- level.setBlock(blockPos1, this.defaultBlockState().setValue(getPropertyForFace(counterClockWise), true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(getPropertyForFace(counterClockWise), true), Block.UPDATE_CLIENTS); + if (cwHasConnectingFace && isAcceptableNeighbour(level, cwTestPos, cwDirection)) { +- level.setBlock(testPos, this.defaultBlockState().setValue(getPropertyForFace(cwDirection), true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, testPos, this.defaultBlockState().setValue(getPropertyForFace(cwDirection), true), Block.UPDATE_CLIENTS); + } else if (ccwHasConnectingFace && isAcceptableNeighbour(level, ccwTestPos, ccwDirection)) { +- level.setBlock(testPos, this.defaultBlockState().setValue(getPropertyForFace(ccwDirection), true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, testPos, this.defaultBlockState().setValue(getPropertyForFace(ccwDirection), true), Block.UPDATE_CLIENTS); } else { - Direction opposite = random1.getOpposite(); - if (value && level.isEmptyBlock(blockPos2) && isAcceptableNeighbour(level, pos.relative(clockWise), opposite)) { -- level.setBlock(blockPos2, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos2, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); - } else if (value1 && level.isEmptyBlock(blockPos3) && isAcceptableNeighbour(level, pos.relative(counterClockWise), opposite)) { -- level.setBlock(blockPos3, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos3, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); - } else if (random.nextFloat() < 0.05 && isAcceptableNeighbour(level, blockPos1.above(), Direction.UP)) { -- level.setBlock(blockPos1, this.defaultBlockState().setValue(UP, true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(UP, true), Block.UPDATE_CLIENTS); + Direction opposite = testDirection.getOpposite(); + if (cwHasConnectingFace && level.isEmptyBlock(cwTestPos) && isAcceptableNeighbour(level, pos.relative(cwDirection), opposite)) { +- level.setBlock(cwTestPos, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, cwTestPos, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); + } else if (ccwHasConnectingFace + && level.isEmptyBlock(ccwTestPos) + && isAcceptableNeighbour(level, pos.relative(ccwDirection), opposite)) { +- level.setBlock(ccwTestPos, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, ccwTestPos, this.defaultBlockState().setValue(getPropertyForFace(opposite), true), Block.UPDATE_CLIENTS); + } else if (random.nextFloat() < 0.05 && isAcceptableNeighbour(level, testPos.above(), Direction.UP)) { +- level.setBlock(testPos, this.defaultBlockState().setValue(UP, true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, testPos, this.defaultBlockState().setValue(UP, true), Block.UPDATE_CLIENTS); } + // CraftBukkit end } - } else if (isAcceptableNeighbour(level, blockPos1, random1)) { -- level.setBlock(pos, state.setValue(getPropertyForFace(random1), true), Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, (BlockState) state.setValue(VineBlock.getPropertyForFace(random1), true), Block.UPDATE_CLIENTS); // CraftBukkit + } else if (isAcceptableNeighbour(level, testPos, testDirection)) { +- level.setBlock(pos, state.setValue(getPropertyForFace(testDirection), true), Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(VineBlock.getPropertyForFace(testDirection), true), Block.UPDATE_CLIENTS); // CraftBukkit } } } else { - if (random1 == Direction.UP && pos.getY() < level.getMaxY()) { - if (this.canSupportAtFace(level, pos, random1)) { + if (testDirection == Direction.UP && pos.getY() < level.getMaxY()) { + if (this.canSupportAtFace(level, pos, testDirection)) { - level.setBlock(pos, state.setValue(UP, true), Block.UPDATE_CLIENTS); + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(UP, true), Block.UPDATE_CLIENTS); // CraftBukkit return; } -@@ -219,7 +_,7 @@ +@@ -221,7 +_,7 @@ } - if (this.hasHorizontalConnection(blockState1)) { -- level.setBlock(blockPos, blockState1, Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState1, Block.UPDATE_CLIENTS); // CraftBukkit + if (this.hasHorizontalConnection(aboveState)) { +- level.setBlock(abovePos, aboveState, Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, abovePos, aboveState, Block.UPDATE_CLIENTS); // CraftBukkit } return; -@@ -233,7 +_,7 @@ - BlockState blockState2 = blockState.isAir() ? this.defaultBlockState() : blockState; - BlockState blockState3 = this.copyRandomFaces(state, blockState2, random); - if (blockState2 != blockState3 && this.hasHorizontalConnection(blockState3)) { -- level.setBlock(blockPos1, blockState3, Block.UPDATE_CLIENTS); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos1, blockState3, Block.UPDATE_CLIENTS); // CraftBukkit +@@ -235,7 +_,7 @@ + BlockState before = belowState.isAir() ? this.defaultBlockState() : belowState; + BlockState after = this.copyRandomFaces(state, before, random); + if (before != after && this.hasHorizontalConnection(after)) { +- level.setBlock(belowPos, after, Block.UPDATE_CLIENTS); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, belowPos, after, Block.UPDATE_CLIENTS); // CraftBukkit } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WallHangingSignBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WallHangingSignBlock.java.patch index b3a0e5ec97b3..b44dd55e2012 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WallHangingSignBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WallHangingSignBlock.java.patch @@ -1,10 +1,11 @@ --- a/net/minecraft/world/level/block/WallHangingSignBlock.java +++ b/net/minecraft/world/level/block/WallHangingSignBlock.java -@@ -174,6 +_,6 @@ +@@ -181,7 +_,7 @@ @Override - public @Nullable BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { -- return createTickerHelper(blockEntityType, BlockEntityType.HANGING_SIGN, SignBlockEntity::tick); + public @Nullable BlockEntityTicker getTicker(final Level level, final BlockState blockState, final BlockEntityType type) { +- return createTickerHelper(type, BlockEntityType.HANGING_SIGN, SignBlockEntity::tick); + return null; // CraftBukkit - remove unnecessary sign ticking } - } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java.patch index ede28b248b61..a6ae841b3849 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java +++ b/net/minecraft/world/level/block/WeatheringCopperGolemStatueBlock.java -@@ -58,16 +_,21 @@ +@@ -64,16 +_,21 @@ return InteractionResult.PASS; } @@ -11,7 +11,7 @@ if (this.getAge().equals(WeatheringCopper.WeatherState.UNAFFECTED)) { CopperGolem copperGolem = copperGolemStatueBlockEntity.removeStatue(state); -- stack.hurtAndBreak(1, player, hand.asEquipmentSlot()); +- itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); if (copperGolem != null) { - level.addFreshEntity(copperGolem); - level.removeBlock(pos, false); @@ -20,7 +20,7 @@ + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { + return InteractionResult.PASS; + } -+ stack.hurtAndBreak(1, player, hand.asEquipmentSlot()); // Paper - moved after event ++ itemStack.hurtAndBreak(1, player, hand.asEquipmentSlot()); // Paper - moved after event + level.addFreshEntity(copperGolem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REANIMATE); // Paper - add SpawnReason + level.setBlock(pos, newState, Block.UPDATE_ALL); + // Paper end - call EntityChangeBlockEvent and spawnReason diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WebBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WebBlock.java.patch index 269b2202f046..0cceaf579007 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WebBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WebBlock.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/level/block/WebBlock.java +++ b/net/minecraft/world/level/block/WebBlock.java -@@ -25,6 +_,7 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -32,6 +_,7 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - Vec3 vec3 = new Vec3(0.25, 0.05F, 0.25); + Vec3 speedMultiplier = new Vec3(0.25, 0.05F, 0.25); if (entity instanceof LivingEntity livingEntity && livingEntity.hasEffect(MobEffects.WEAVING)) { - vec3 = new Vec3(0.5, 0.25, 0.5); + speedMultiplier = new Vec3(0.5, 0.25, 0.5); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WeightedPressurePlateBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WeightedPressurePlateBlock.java.patch index 07cf136cbf0a..323d70dfe997 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WeightedPressurePlateBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WeightedPressurePlateBlock.java.patch @@ -3,11 +3,11 @@ @@ -39,7 +_,25 @@ @Override - protected int getSignalStrength(Level level, BlockPos pos) { -- int min = Math.min(getEntityCount(level, TOUCH_AABB.move(pos), Entity.class), this.maxWeight); + protected int getSignalStrength(final Level level, final BlockPos pos) { +- int count = Math.min(getEntityCount(level, TOUCH_AABB.move(pos), Entity.class), this.maxWeight); + // CraftBukkit start + // int min = Math.min(getEntityCount(level, TOUCH_AABB.move(pos), Entity.class), this.maxWeight); -+ int min = 0; ++ int count = 0; + for (Entity entity : getEntities(level, TOUCH_AABB.move(pos), Entity.class)) { + org.bukkit.event.Cancellable cancellable; + @@ -20,10 +20,10 @@ + + // We only want to block turning the plate on if all events are cancelled + if (!cancellable.isCancelled()) { -+ min++; ++ count++; + } + } + // CraftBukkit end - if (min > 0) { - float f = (float)Math.min(this.maxWeight, min) / this.maxWeight; - return Mth.ceil(f * 15.0F); + if (count > 0) { + float percent = (float)Math.min(this.maxWeight, count) / this.maxWeight; + return Mth.ceil(percent * 15.0F); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WitherRoseBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WitherRoseBlock.java.patch index 06ebeb800603..681137eaa139 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WitherRoseBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WitherRoseBlock.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/WitherRoseBlock.java +++ b/net/minecraft/world/level/block/WitherRoseBlock.java -@@ -64,11 +_,12 @@ - - @Override - protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean pastEdges) { +@@ -72,11 +_,12 @@ + final InsideBlockEffectApplier effectApplier, + final boolean isPrecise + ) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (level instanceof ServerLevel serverLevel && level.getDifficulty() != Difficulty.PEACEFUL diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch index a1496c38cf0b..5aa9ac611b52 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch @@ -3,37 +3,37 @@ @@ -49,6 +_,7 @@ } - public static void checkSpawn(Level level, BlockPos pos, SkullBlockEntity blockEntity) { + public static void checkSpawn(final Level level, final BlockPos pos, final SkullBlockEntity placedSkull) { + if (level.captureBlockStates) return; // CraftBukkit if (!level.isClientSide()) { - BlockState blockState = blockEntity.getBlockState(); - boolean flag = blockState.is(Blocks.WITHER_SKELETON_SKULL) || blockState.is(Blocks.WITHER_SKELETON_WALL_SKULL); + BlockState blockState = placedSkull.getBlockState(); + boolean correctBlock = blockState.is(Blocks.WITHER_SKELETON_SKULL) || blockState.is(Blocks.WITHER_SKELETON_WALL_SKULL); @@ -57,7 +_,7 @@ - if (blockPatternMatch != null) { + if (match != null) { WitherBoss witherBoss = EntityType.WITHER.create(level, EntitySpawnReason.TRIGGERED); if (witherBoss != null) { -- CarvedPumpkinBlock.clearPatternBlocks(level, blockPatternMatch); -+ // CarvedPumpkinBlock.clearPatternBlocks(level, blockPatternMatch); // CraftBukkit - move down - BlockPos pos1 = blockPatternMatch.getBlock(1, 2, 0).getPos(); +- CarvedPumpkinBlock.clearPatternBlocks(level, match); ++ // CarvedPumpkinBlock.clearPatternBlocks(level, match); // CraftBukkit - move down + BlockPos spawnPos = match.getBlock(1, 2, 0).getPos(); witherBoss.snapTo( - pos1.getX() + 0.5, + spawnPos.getX() + 0.5, @@ -68,12 +_,18 @@ ); - witherBoss.yBodyRot = blockPatternMatch.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F; + witherBoss.yBodyRot = match.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F; witherBoss.makeInvulnerable(); + // CraftBukkit start + if (!level.addFreshEntity(witherBoss, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_WITHER)) { + return; + } -+ CarvedPumpkinBlock.clearPatternBlocks(level, blockPatternMatch); // CraftBukkit - from above ++ CarvedPumpkinBlock.clearPatternBlocks(level, match); // CraftBukkit - from above + // CraftBukkit end - for (ServerPlayer serverPlayer : level.getEntitiesOfClass(ServerPlayer.class, witherBoss.getBoundingBox().inflate(50.0))) { - CriteriaTriggers.SUMMONED_ENTITY.trigger(serverPlayer, witherBoss); + for (ServerPlayer player : level.getEntitiesOfClass(ServerPlayer.class, witherBoss.getBoundingBox().inflate(50.0))) { + CriteriaTriggers.SUMMONED_ENTITY.trigger(player, witherBoss); } - level.addFreshEntity(witherBoss); + // level.addFreshEntity(witherBoss); // CraftBukkit - moved up - CarvedPumpkinBlock.updatePatternBlocks(level, blockPatternMatch); + CarvedPumpkinBlock.updatePatternBlocks(level, match); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch index f068f0f98742..6157f3afddab 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch @@ -1,14 +1,16 @@ --- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -105,11 +_,49 @@ +@@ -109,13 +_,51 @@ }; public final Reference2IntOpenHashMap>> recipesUsed = new Reference2IntOpenHashMap<>(); private final RecipeManager.CachedCheck quickCheck; + public final RecipeType recipeType; // Paper - cook speed multiplier API + public double cookSpeedMultiplier = 1.0; // Paper - cook speed multiplier API - protected AbstractFurnaceBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState, RecipeType recipeType) { - super(type, pos, blockState); + protected AbstractFurnaceBlockEntity( + final BlockEntityType type, final BlockPos worldPosition, final BlockState blockState, final RecipeType recipeType + ) { + super(type, worldPosition, blockState); this.quickCheck = RecipeManager.createCheck(recipeType); - } + this.recipeType = recipeType; // Paper - cook speed multiplier API @@ -49,9 +51,9 @@ + } + // CraftBukkit end - private boolean isLit() { - return this.litTimeRemaining > 0; -@@ -126,6 +_,7 @@ + @Override + protected void loadAdditional(final ValueInput input) { +@@ -128,6 +_,7 @@ this.litTotalTime = input.getShortOr("lit_total_time", (short)0); this.recipesUsed.clear(); this.recipesUsed.putAll(input.read("RecipesUsed", RECIPES_USED_CODEC).orElse(Map.of())); @@ -59,7 +61,7 @@ } @Override -@@ -135,6 +_,7 @@ +@@ -137,6 +_,7 @@ output.putShort("cooking_total_time", (short)this.cookingTotalTime); output.putShort("lit_time_remaining", (short)this.litTimeRemaining); output.putShort("lit_total_time", (short)this.litTotalTime); @@ -67,216 +69,208 @@ ContainerHelper.saveAllItems(output, this.items); output.store("RecipesUsed", RECIPES_USED_CODEC, this.recipesUsed); } -@@ -161,11 +_,22 @@ - - int maxStackSize = furnace.getMaxStackSize(); - if (!furnace.isLit() && canBurn(level.registryAccess(), recipeHolder, singleRecipeInput, furnace.items, maxStackSize)) { -- furnace.litTimeRemaining = furnace.getBurnDuration(level.fuelValues(), itemStack); -+ // CraftBukkit start -+ org.bukkit.craftbukkit.inventory.CraftItemStack fuel = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); -+ -+ org.bukkit.event.inventory.FurnaceBurnEvent furnaceBurnEvent = new org.bukkit.event.inventory.FurnaceBurnEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), -+ fuel, -+ furnace.getBurnDuration(level.fuelValues(), itemStack) -+ ); -+ if (!furnaceBurnEvent.callEvent()) return; -+ // CraftBukkit end -+ -+ furnace.litTimeRemaining = furnaceBurnEvent.getBurnTime(); // CraftBukkit - respect event output - furnace.litTotalTime = furnace.litTimeRemaining; -- if (furnace.isLit()) { -+ if (furnace.isLit() && furnaceBurnEvent.isBurning()) { // CraftBukkit - respect event output - flag = true; -- if (flag2) { -+ if (flag2 && furnaceBurnEvent.willConsumeFuel()) { // Paper - add consumeFuel to FurnaceBurnEvent - Item item = itemStack.getItem(); - itemStack.shrink(1); - if (itemStack.isEmpty()) { -@@ -176,11 +_,28 @@ - } +@@ -166,24 +_,48 @@ + int maxStackSize = entity.getMaxStackSize(); + ItemStack burnResult = recipe.value().assemble(input); + if (!burnResult.isEmpty() && canBurn(entity.items, maxStackSize, burnResult)) { ++ // CraftBukkit start ++ org.bukkit.event.inventory.FurnaceBurnEvent furnaceBurnEvent = new org.bukkit.event.inventory.FurnaceBurnEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(fuel), ++ entity.getBurnDuration(level.fuelValues(), fuel) ++ ); ++ if (!furnaceBurnEvent.callEvent()) return; ++ // CraftBukkit end + if (!isLit) { +- int newLitTime = entity.getBurnDuration(level.fuelValues(), fuel); ++ int newLitTime = furnaceBurnEvent.getBurnTime(); // CraftBukkit - respect event output + entity.litTimeRemaining = newLitTime; + entity.litTotalTime = newLitTime; +- if (newLitTime > 0) { ++ if (newLitTime > 0 && furnaceBurnEvent.isBurning()) { // CraftBukkit - respect event output // TODO - snapshot - double check surrounding diff post squash ++ if (furnaceBurnEvent.willConsumeFuel()) { // Paper - add consumeFuel to FurnaceBurnEvent + consumeFuel(entity.items, fuel); ++ } // Paper - add consumeFuel to FurnaceBurnEvent + isLit = true; + changed = true; + } + } - if (furnace.isLit() && canBurn(level.registryAccess(), recipeHolder, singleRecipeInput, furnace.items, maxStackSize)) { -+ // CraftBukkit start -+ if (recipeHolder != null && furnace.cookingTimer == 0) { -+ org.bukkit.craftbukkit.inventory.CraftItemStack source = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(furnace.items.get(0)); -+ org.bukkit.inventory.CookingRecipe recipe = (org.bukkit.inventory.CookingRecipe) recipeHolder.toBukkitRecipe(); -+ -+ org.bukkit.event.inventory.FurnaceStartSmeltEvent event = new org.bukkit.event.inventory.FurnaceStartSmeltEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), -+ source, -+ recipe, -+ getTotalCookTime(level, furnace, furnace.recipeType, furnace.cookSpeedMultiplier) // Paper - cook speed multiplier API -+ ); -+ event.callEvent(); + if (isLit) { ++ // CraftBukkit start ++ if (entity.cookingTimer == 0) { ++ org.bukkit.event.inventory.FurnaceStartSmeltEvent event = new org.bukkit.event.inventory.FurnaceStartSmeltEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(ingredient), ++ (org.bukkit.inventory.CookingRecipe) recipe.toBukkitRecipe(), ++ getTotalCookTime(level, entity, entity.recipeType, entity.cookSpeedMultiplier) // Paper - cook speed multiplier API ++ ); ++ event.callEvent(); + -+ furnace.cookingTotalTime = event.getTotalCookTime(); -+ } -+ // CraftBukkit end -+ - furnace.cookingTimer++; -- if (furnace.cookingTimer == furnace.cookingTotalTime) { -+ if (furnace.cookingTimer >= furnace.cookingTotalTime) { // Paper - cook speed multiplier API - furnace.cookingTimer = 0; -- furnace.cookingTotalTime = getTotalCookTime(level, furnace); -- if (burn(level.registryAccess(), recipeHolder, singleRecipeInput, furnace.items, maxStackSize)) { -+ furnace.cookingTotalTime = getTotalCookTime(level, furnace, furnace.recipeType, furnace.cookSpeedMultiplier); // Paper - cook speed multiplier API -+ if (burn(level.registryAccess(), recipeHolder, singleRecipeInput, furnace.items, maxStackSize, level, furnace.worldPosition)) { // CraftBukkit - furnace.setRecipeUsed(recipeHolder); - } ++ entity.cookingTotalTime = event.getTotalCookTime(); ++ } ++ // CraftBukkit end + entity.cookingTimer++; +- if (entity.cookingTimer == entity.cookingTotalTime) { ++ if (entity.cookingTimer >= entity.cookingTotalTime) { // Paper - cook speed multiplier API + entity.cookingTimer = 0; +- entity.cookingTotalTime = recipe.value().cookingTime(); +- burn(entity.items, ingredient, burnResult); ++ entity.cookingTotalTime = getTotalCookTime(level, entity, entity.recipeType, entity.cookSpeedMultiplier); // Paper - cook speed multiplier API ++ if (burn(entity.items, ingredient, burnResult, recipe, level, entity.worldPosition)) { // CraftBukkit - add level & pos // Paper - make burn return a boolean again, add recipe + entity.setRecipeUsed(recipe); ++ } // Paper + changed = true; + } + } else { +@@ -233,28 +_,63 @@ + } + } -@@ -234,17 +_,47 @@ - @Nullable RecipeHolder recipe, - SingleRecipeInput recipeInput, - NonNullList items, -- int maxStackSize -+ int maxStackSize, -+ net.minecraft.world.level.Level level, // CraftBukkit -+ BlockPos blockPos // CraftBukkit - ) { - if (recipe != null && canBurn(registryAccess, recipe, recipeInput, items, maxStackSize)) { -- ItemStack itemStack = items.get(0); -- ItemStack itemStack1 = recipe.value().assemble(recipeInput, registryAccess); -- ItemStack itemStack2 = items.get(2); -+ ItemStack itemStack = items.get(0); final ItemStack ingredient = itemStack; // Paper - OBFHELPER -+ ItemStack itemStack1 = recipe.value().assemble(recipeInput, registryAccess); ItemStack result = itemStack1; // Paper - OBFHELPER -+ ItemStack itemStack2 = items.get(2); final ItemStack existingResults = itemStack2; // Paper - OBFHELPER -+ // CraftBukkit start - fire FurnaceSmeltEvent -+ org.bukkit.craftbukkit.inventory.CraftItemStack apiIngredient = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(ingredient); -+ org.bukkit.inventory.ItemStack apiResult = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(result); +- private static void burn(final NonNullList items, final ItemStack inputItemStack, final ItemStack result) { ++ private static boolean burn(final NonNullList items, final ItemStack inputItemStack, ItemStack result, RecipeHolder recipe, final net.minecraft.world.level.Level level, final BlockPos blockPos) { // CraftBukkit + ItemStack resultItemStack = items.get(2); ++ // CraftBukkit start - fire FurnaceSmeltEvent ++ org.bukkit.craftbukkit.inventory.CraftItemStack apiIngredient = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(inputItemStack); ++ org.bukkit.inventory.ItemStack apiResult = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(result); + -+ org.bukkit.event.inventory.FurnaceSmeltEvent furnaceSmeltEvent = new org.bukkit.event.inventory.FurnaceSmeltEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), -+ apiIngredient, -+ apiResult, -+ (org.bukkit.inventory.CookingRecipe) recipe.toBukkitRecipe() // Paper - Add recipe to cook events -+ ); -+ if (!furnaceSmeltEvent.callEvent()) return false; ++ org.bukkit.event.inventory.FurnaceSmeltEvent furnaceSmeltEvent = new org.bukkit.event.inventory.FurnaceSmeltEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), ++ apiIngredient, ++ apiResult, ++ (org.bukkit.inventory.CookingRecipe) recipe.toBukkitRecipe() // Paper - Add recipe to cook events ++ ); ++ if (!furnaceSmeltEvent.callEvent()) return false; + -+ apiResult = furnaceSmeltEvent.getResult(); -+ itemStack1 = result = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(apiResult); ++ apiResult = furnaceSmeltEvent.getResult(); ++ result = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(apiResult); + -+ if (!result.isEmpty()) { -+ if (existingResults.isEmpty()) { -+ items.set(SLOT_RESULT, result.copy()); -+ } else if (org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(existingResults).isSimilar(apiResult)) { -+ existingResults.grow(result.getCount()); -+ } else { -+ return false; -+ } ++ if (!result.isEmpty()) { ++ if (resultItemStack.isEmpty()) { ++ items.set(SLOT_RESULT, result.copy()); ++ } else if (org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(resultItemStack).isSimilar(apiResult)) { ++ resultItemStack.grow(result.getCount()); ++ } else { ++ return false; + } -+ -+ /* - if (itemStack2.isEmpty()) { - items.set(2, itemStack1.copy()); - } else if (ItemStack.isSameItemSameComponents(itemStack2, itemStack1)) { - itemStack2.grow(1); - } -+ */ -+ // CraftBukkit end ++ } ++ /* + if (resultItemStack.isEmpty()) { + items.set(2, result.copy()); + } else { + resultItemStack.grow(result.getCount()); + } ++ */ ++ // CraftBukkit end - if (itemStack.is(Blocks.WET_SPONGE.asItem()) && !items.get(1).isEmpty() && items.get(1).is(Items.BUCKET)) { - items.set(1, new ItemStack(Items.WATER_BUCKET)); -@@ -261,9 +_,16 @@ - return fuelValues.burnDuration(stack); + if (inputItemStack.is(Items.WET_SPONGE) && !items.get(1).isEmpty() && items.get(1).is(Items.BUCKET)) { + items.set(1, new ItemStack(Items.WATER_BUCKET)); + } + + inputItemStack.shrink(1); ++ return true; // Paper - make burn return a boolean again + } + + protected int getBurnDuration(final FuelValues fuelValues, final ItemStack itemStack) { + return fuelValues.burnDuration(itemStack); } -- public static int getTotalCookTime(ServerLevel level, AbstractFurnaceBlockEntity furnace) { -+ public static int getTotalCookTime(@Nullable ServerLevel level, AbstractFurnaceBlockEntity furnace, RecipeType recipeType, double cookSpeedMultiplier) { // Paper - cook speed multiplier API - SingleRecipeInput singleRecipeInput = new SingleRecipeInput(furnace.getItem(0)); -- return furnace.quickCheck.getRecipeFor(singleRecipeInput, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(200); +- public static int getTotalCookTime(final ServerLevel level, final AbstractFurnaceBlockEntity entity) { ++ public static int getTotalCookTime(final @Nullable ServerLevel level, final AbstractFurnaceBlockEntity entity, final RecipeType recipeType, final double cookSpeedMultiplier) { // Paper - cook speed multiplier API + SingleRecipeInput input = new SingleRecipeInput(entity.getItem(0)); +- return entity.quickCheck.getRecipeFor(input, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(200); + // Paper start - cook speed multiplier API + /* Scale the recipe's cooking time to the current cookSpeedMultiplier */ + int cookTime = level != null -+ ? furnace.quickCheck.getRecipeFor(singleRecipeInput, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(BURN_TIME_STANDARD) ++ ? entity.quickCheck.getRecipeFor(input, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(BURN_TIME_STANDARD) + /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */ -+ : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, singleRecipeInput, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(BURN_TIME_STANDARD)); ++ : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, input, level).map(recipeHolder -> recipeHolder.value().cookingTime()).orElse(BURN_TIME_STANDARD)); + return (int) Math.ceil (cookTime / cookSpeedMultiplier); + // Paper end - cook speed multiplier API } @Override -@@ -307,7 +_,7 @@ - this.items.set(index, stack); - stack.limitSize(this.getMaxStackSize(stack)); - if (index == 0 && !flag && this.level instanceof ServerLevel serverLevel) { +@@ -298,7 +_,7 @@ + this.items.set(slot, itemStack); + itemStack.limitSize(this.getMaxStackSize(itemStack)); + if (slot == 0 && !same && this.level instanceof ServerLevel serverLevel) { - this.cookingTotalTime = getTotalCookTime(serverLevel, this); + this.cookingTotalTime = getTotalCookTime(serverLevel, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API this.cookingTimer = 0; this.setChanged(); } -@@ -342,8 +_,8 @@ - public void awardUsedRecipes(Player player, List items) { +@@ -333,8 +_,8 @@ + public void awardUsedRecipes(final Player player, final List itemStacks) { } -- public void awardUsedRecipesAndPopExperience(ServerPlayer player) { -- List> recipesToAwardAndPopExperience = this.getRecipesToAwardAndPopExperience(player.level(), player.position()); -+ public void awardUsedRecipesAndPopExperience(ServerPlayer player, ItemStack itemstack, int amount) { // CraftBukkit -+ List> recipesToAwardAndPopExperience = this.getRecipesToAwardAndPopExperience(player.level(), player.position(), this.worldPosition, player, itemstack, amount); // CraftBukkit - overload for exp spawn events - player.awardRecipes(recipesToAwardAndPopExperience); +- public void awardUsedRecipesAndPopExperience(final ServerPlayer player) { +- List> recipesToAward = this.getRecipesToAwardAndPopExperience(player.level(), player.position()); ++ public void awardUsedRecipesAndPopExperience(final ServerPlayer player, final ItemStack itemStack, final int amount) { // CraftBukkit ++ List> recipesToAward = this.getRecipesToAwardAndPopExperience(player.level(), player.position(), this.worldPosition, player, itemStack, amount); // CraftBukkit - overload for exp spawn events + player.awardRecipes(recipesToAward); - for (RecipeHolder recipeHolder : recipesToAwardAndPopExperience) { -@@ -354,30 +_,60 @@ + for (RecipeHolder recipe : recipesToAward) { +@@ -345,30 +_,60 @@ } - public List> getRecipesToAwardAndPopExperience(ServerLevel level, Vec3 popVec) { -+ // CraftBukkit start -+ return this.getRecipesToAwardAndPopExperience(level, popVec, this.worldPosition, null, null, 0); + public List> getRecipesToAwardAndPopExperience(final ServerLevel level, final Vec3 position) { ++ // CraftBukkit start ++ return this.getRecipesToAwardAndPopExperience(level, position, this.worldPosition, null, null, 0); + } -+ public List> getRecipesToAwardAndPopExperience(ServerLevel level, Vec3 popVec, BlockPos blockPos, ServerPlayer serverPlayer, ItemStack itemStack, int amount) { -+ // CraftBukkit end - List> list = Lists.newArrayList(); ++ public List> getRecipesToAwardAndPopExperience(final ServerLevel level, final Vec3 position, final BlockPos blockPos, final @Nullable ServerPlayer serverPlayer, final @Nullable ItemStack itemStack, final int amount) { ++ // CraftBukkit end + List> recipesToAward = Lists.newArrayList(); for (Entry>> entry : this.recipesUsed.reference2IntEntrySet()) { - level.recipeAccess().byKey(entry.getKey()).ifPresent(recipeHolder -> { -+ if (!(recipeHolder.value() instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes - list.add((RecipeHolder)recipeHolder); -- createExperience(level, popVec, entry.getIntValue(), ((AbstractCookingRecipe)recipeHolder.value()).experience()); -+ createExperience(level, popVec, entry.getIntValue(), ((AbstractCookingRecipe)recipeHolder.value()).experience(), blockPos, serverPlayer, itemStack, amount); // Paper - don't process non-cooking recipes + level.recipeAccess().byKey(entry.getKey()).ifPresent(recipe -> { ++ if (!(recipe.value() instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes + recipesToAward.add((RecipeHolder)recipe); +- createExperience(level, position, entry.getIntValue(), ((AbstractCookingRecipe)recipe.value()).experience()); ++ createExperience(level, position, entry.getIntValue(), ((AbstractCookingRecipe)recipe.value()).experience(), blockPos, serverPlayer, itemStack, amount); // Paper - don't process non-cooking recipes }); } - return list; + return recipesToAward; } -- private static void createExperience(ServerLevel level, Vec3 popVec, int recipeIndex, float experience) { -+ private static void createExperience(ServerLevel level, Vec3 popVec, int recipeIndex, float experience, BlockPos blockPos, ServerPlayer serverPlayer, ItemStack itemStack, int amount) { // CraftBukkit - int floor = Mth.floor(recipeIndex * experience); - float fraction = Mth.frac(recipeIndex * experience); - if (fraction != 0.0F && level.random.nextFloat() < fraction) { - floor++; +- private static void createExperience(final ServerLevel level, final Vec3 position, final int amount, final float value) { ++ private static void createExperience(final ServerLevel level, final Vec3 position, final int amount, final float value, final BlockPos blockPos, final ServerPlayer player, final ItemStack itemStack, final int removeCount) { + int xpReward = Mth.floor(amount * value); + float xpFraction = Mth.frac(amount * value); + if (xpFraction != 0.0F && level.getRandom().nextFloat() < xpFraction) { + xpReward++; } -- ExperienceOrb.award(level, popVec, floor); +- ExperienceOrb.award(level, position, xpReward); + // CraftBukkit start - fire FurnaceExtractEvent / BlockExpEvent + org.bukkit.event.block.BlockExpEvent event; -+ if (amount != 0) { ++ if (removeCount != 0) { + event = new org.bukkit.event.inventory.FurnaceExtractEvent( -+ serverPlayer.getBukkitEntity(), ++ player.getBukkitEntity(), + org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), + itemStack.asBukkitCopy(), -+ amount, -+ floor ++ removeCount, ++ xpReward + ); + } else { + event = new org.bukkit.event.block.BlockExpEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), -+ floor ++ xpReward + ); + } + event.callEvent(); -+ floor = event.getExpToDrop(); ++ xpReward = event.getExpToDrop(); + // CraftBukkit end + -+ ExperienceOrb.awardWithDirection(level, popVec, net.minecraft.world.phys.Vec3.ZERO, floor, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, serverPlayer, null); // Paper ++ ExperienceOrb.awardWithDirection(level, position, net.minecraft.world.phys.Vec3.ZERO, xpReward, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, player, null); // Paper } @Override - public void fillStackedContents(StackedItemContents stackedContents) { + public void fillStackedContents(final StackedItemContents contents) { + // Paper start - don't account fuel stack (fixes MC-243057) -+ stackedContents.accountStack(this.items.get(SLOT_INPUT)); -+ stackedContents.accountStack(this.items.get(SLOT_RESULT)); ++ contents.accountStack(this.items.get(SLOT_INPUT)); ++ contents.accountStack(this.items.get(SLOT_RESULT)); + // Paper end - don't account fuel stack (fixes MC-243057) for (ItemStack itemStack : this.items) { - stackedContents.accountStack(itemStack); + contents.accountStack(itemStack); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BannerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BannerBlockEntity.java.patch index 6631c94aa4ed..88c69b254024 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BannerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BannerBlockEntity.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/block/entity/BannerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BannerBlockEntity.java -@@ -49,7 +_,7 @@ +@@ -48,7 +_,7 @@ @Override - protected void saveAdditional(ValueOutput output) { + protected void saveAdditional(final ValueOutput output) { super.saveAdditional(output); - if (!this.patterns.equals(BannerPatternLayers.EMPTY)) { + if (!this.patterns.equals(BannerPatternLayers.EMPTY) || serialisingForNetwork.get()) { // Paper - always send patterns to client output.store("patterns", BannerPatternLayers.CODEC, this.patterns); } -@@ -60,7 +_,7 @@ - protected void loadAdditional(ValueInput input) { +@@ -59,7 +_,7 @@ + protected void loadAdditional(final ValueInput input) { super.loadAdditional(input); this.name = parseCustomNameSafe(input, "CustomName"); - this.patterns = input.read("patterns", BannerPatternLayers.CODEC).orElse(BannerPatternLayers.EMPTY); @@ -18,14 +18,14 @@ } @Override -@@ -68,9 +_,18 @@ +@@ -67,9 +_,18 @@ return ClientboundBlockEntityDataPacket.create(this); } + // Paper start - always send patterns to client + ThreadLocal serialisingForNetwork = ThreadLocal.withInitial(() -> Boolean.FALSE); @Override - public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + public CompoundTag getUpdateTag(final HolderLookup.Provider registries) { + final Boolean wasSerialisingForNetwork = serialisingForNetwork.get(); + try { + serialisingForNetwork.set(Boolean.TRUE); @@ -37,16 +37,16 @@ } public BannerPatternLayers getPatterns() { -@@ -90,7 +_,7 @@ +@@ -89,7 +_,7 @@ @Override - protected void applyImplicitComponents(DataComponentGetter componentGetter) { - super.applyImplicitComponents(componentGetter); -- this.patterns = componentGetter.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); -+ this.setPatterns(componentGetter.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits - this.name = componentGetter.get(DataComponents.CUSTOM_NAME); + protected void applyImplicitComponents(final DataComponentGetter components) { + super.applyImplicitComponents(components); +- this.patterns = components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); ++ this.setPatterns(components.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits + this.name = components.get(DataComponents.CUSTOM_NAME); } -@@ -106,4 +_,13 @@ +@@ -105,4 +_,13 @@ output.discard("patterns"); output.discard("CustomName"); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch index 262672ce2551..c0cf3395c308 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -24,6 +_,40 @@ +@@ -25,6 +_,40 @@ import net.minecraft.world.level.storage.ValueOutput; public class BarrelBlockEntity extends RandomizableContainerBlockEntity { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch index 1c321829b731..d385be38a528 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch @@ -3,20 +3,20 @@ @@ -66,14 +_,19 @@ protected abstract Component getDefaultName(); - public boolean canOpen(Player player) { + public boolean canOpen(final Player player) { - return this.lockKey.canUnlock(player); + return org.bukkit.craftbukkit.event.CraftEventFactory.callBlockLockCheckEvent(this, this.lockKey, this.getDisplayName(), player); // Paper - Call BlockLockCheckEvent } - public static void sendChestLockedNotifications(Vec3 pos, Player player, Component displayName) { + public static void sendChestLockedNotifications(final Vec3 pos, final Player player, final Component displayName) { + // Paper start - BlockLockCheckEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.sendChestLockedNotifications(pos)) { + return; + } + // Paper end - BlockLockCheckEvent Level level = player.level(); -- player.displayClientMessage(Component.translatable("container.isLocked", displayName), true); -+ player.displayClientMessage(Component.translatable("container.isLocked", displayName), true); // Paper - diff on change +- player.sendOverlayMessage(Component.translatable("container.isLocked", displayName)); ++ player.sendOverlayMessage(Component.translatable("container.isLocked", displayName)); // Paper - diff on change if (!level.isClientSide()) { - level.playSound(null, pos.x(), pos.y(), pos.z(), SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); + level.playSound(null, pos.x(), pos.y(), pos.z(), SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper - diff on change diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch index 74e7cf991841..e15d7d61fc34 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -107,6 +_,51 @@ +@@ -111,6 +_,51 @@ return 3; } }; @@ -50,38 +50,30 @@ + } + // Paper end - Custom beacon ranges - static @Nullable Holder filterEffect(@Nullable Holder effect) { + private static @Nullable Holder filterEffect(final @Nullable Holder effect) { return VALID_EFFECTS.contains(effect) ? effect : null; -@@ -163,17 +_,26 @@ - blockEntity.lastCheckY++; - } - -- int i = blockEntity.levels; -+ int i = blockEntity.levels; final int originalLevels = i; // Paper - OBFHELPER - if (level.getGameTime() % 80L == 0L) { - if (!blockEntity.beamSections.isEmpty()) { - blockEntity.levels = updateBase(level, x, y, z); +@@ -174,10 +_,19 @@ } - if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) { -- applyEffects(level, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower); -+ applyEffects(level, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges + if (entity.levels > 0 && !entity.beamSections.isEmpty()) { +- applyEffects(level, pos, entity.levels, entity.primaryPower, entity.secondaryPower); ++ applyEffects(level, pos, entity.levels, entity.primaryPower, entity.secondaryPower, entity); // Paper - Custom beacon ranges playSound(level, pos, SoundEvents.BEACON_AMBIENT); } } + // Paper start - beacon activation/deactivation events -+ if (originalLevels <= 0 && blockEntity.levels > 0) { ++ if (previousLevels <= 0 && entity.levels > 0) { + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + new io.papermc.paper.event.block.BeaconActivatedEvent(block).callEvent(); -+ } else if (originalLevels > 0 && blockEntity.levels <= 0) { ++ } else if (previousLevels > 0 && entity.levels <= 0) { + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + new io.papermc.paper.event.block.BeaconDeactivatedEvent(block).callEvent(); + } + // Paper end - beacon activation/deactivation events - if (blockEntity.lastCheckY >= height) { - blockEntity.lastCheckY = level.getMinY() - 1; -@@ -224,35 +_,100 @@ + if (entity.lastCheckY >= lastSetBlock) { + entity.lastCheckY = level.getMinY() - 1; +@@ -228,7 +_,15 @@ @Override public void setRemoved() { @@ -97,46 +89,40 @@ super.setRemoved(); } -+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - pass beacon block entity - private static void applyEffects( - Level level, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect +@@ -238,29 +_,78 @@ + final int levels, + final @Nullable Holder primaryPower, + final @Nullable Holder secondaryPower ++ , final BeaconBlockEntity entity // Paper - pass beacon block entity ) { -+ // Paper start - pass beacon block entity -+ applyEffects(level, pos, beaconLevel, primaryEffect, secondaryEffect, null); -+ } -+ -+ private static void applyEffects( -+ Level level, BlockPos pos, int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect, @Nullable BeaconBlockEntity blockEntity -+ ) { -+ // Paper end - pass beacon block entity - if (!level.isClientSide() && primaryEffect != null) { -- double d = beaconLevel * 10 + 10; -- int i = 0; -- if (beaconLevel >= 4 && Objects.equals(primaryEffect, secondaryEffect)) { -- i = 1; + if (!level.isClientSide() && primaryPower != null) { +- double range = levels * 10 + 10; +- int baseAmp = 0; +- if (levels >= 4 && Objects.equals(primaryPower, secondaryPower)) { +- baseAmp = 1; - } - -- int i1 = (9 + beaconLevel * 2) * 20; -- AABB aabb = new AABB(pos).inflate(d).expandTowards(0.0, level.getHeight(), 0.0); -- List entitiesOfClass = level.getEntitiesOfClass(Player.class, aabb); +- int durationTicks = (9 + levels * 2) * 20; +- AABB bb = new AABB(worldPosition).inflate(range).expandTowards(0.0, level.getHeight(), 0.0); +- List players = level.getEntitiesOfClass(Player.class, bb); - -- for (Player player : entitiesOfClass) { -- player.addEffect(new MobEffectInstance(primaryEffect, i1, i, true, true)); +- for (Player player : players) { +- player.addEffect(new MobEffectInstance(primaryPower, durationTicks, baseAmp, true, true)); - } - -- if (beaconLevel >= 4 && !Objects.equals(primaryEffect, secondaryEffect) && secondaryEffect != null) { -- for (Player player : entitiesOfClass) { -- player.addEffect(new MobEffectInstance(secondaryEffect, i1, 0, true, true)); -+ double d = computeBeaconRange(beaconLevel); // Paper - diff out applyEffects logic components - see below -+ int i = computeEffectAmplifier(beaconLevel, primaryEffect, secondaryEffect); // Paper - diff out applyEffects logic components - see below +- if (levels >= 4 && !Objects.equals(primaryPower, secondaryPower) && secondaryPower != null) { +- for (Player player : players) { +- player.addEffect(new MobEffectInstance(secondaryPower, durationTicks, 0, true, true)); ++ double range = computeBeaconRange(levels); // Paper - diff out applyEffects logic components - see below ++ int baseAmp = computeEffectAmplifier(levels, primaryPower, secondaryPower); // Paper - diff out applyEffects logic components - see below + -+ int i1 = computeEffectDuration(beaconLevel); // Paper - diff out applyEffects logic components - see below -+ List entitiesOfClass = getHumansInRange(level, pos, beaconLevel, blockEntity); // Paper - diff out applyEffects logic components - see below ++ int durationTicks = computeEffectDuration(levels); // Paper - diff out applyEffects logic components - see below ++ List players = getHumansInRange(level, worldPosition, levels, entity); // Paper - diff out applyEffects logic components - see below + -+ applyEffectsAndCallEvent(level, pos, entitiesOfClass, new MobEffectInstance(primaryEffect, i1, i, true, true), true); // Paper - BeaconEffectEvent ++ applyEffectsAndCallEvent(level, worldPosition, players, new MobEffectInstance(primaryPower, durationTicks, baseAmp, true, true), true); // Paper - BeaconEffectEvent + -+ if (hasSecondaryEffect(beaconLevel, primaryEffect, secondaryEffect)) { // Paper - diff out applyEffects logic components - see below -+ applyEffectsAndCallEvent(level, pos, entitiesOfClass, new MobEffectInstance(secondaryEffect, i1, 0, true, true), false); // Paper - BeaconEffectEvent ++ if (hasSecondaryEffect(levels, primaryPower, secondaryPower)) { // Paper - diff out applyEffects logic components - see below ++ applyEffectsAndCallEvent(level, worldPosition, players, new MobEffectInstance(secondaryPower, durationTicks, 0, true, true), false); // Paper - BeaconEffectEvent + } + } + } @@ -148,11 +134,11 @@ + } + + private static int computeEffectAmplifier(final int beaconLevel, @Nullable Holder primaryEffect, @Nullable Holder secondaryEffect) { -+ int i = 0; ++ int baseAmp = 0; + if (beaconLevel >= 4 && Objects.equals(primaryEffect, secondaryEffect)) { -+ i = 1; ++ baseAmp = 1; + } -+ return i; ++ return baseAmp; + } + + private static double computeBeaconRange(final int beaconLevel) { @@ -160,11 +146,11 @@ + } + + public static List getHumansInRange(final Level level, final BlockPos pos, final int beaconLevel, final @Nullable BeaconBlockEntity blockEntity) { -+ final double d = blockEntity != null ? blockEntity.getEffectRange() : computeBeaconRange(beaconLevel); -+ AABB aabb = new AABB(pos).inflate(d).expandTowards(0.0, level.getHeight(), 0.0); // Diff from applyEffects ++ final double range = blockEntity != null ? blockEntity.getEffectRange() : computeBeaconRange(beaconLevel); ++ AABB aabb = new AABB(pos).inflate(range).expandTowards(0.0, level.getHeight(), 0.0); // Diff from applyEffects + // Improve performance of human lookup by switching to a global player iteration when searching over 128 blocks + List list; -+ if (d <= 128.0) { ++ if (range <= 128.0) { + list = level.getEntitiesOfClass(Player.class, aabb); // Diff from applyEffect + } else { + list = new java.util.ArrayList<>(); @@ -198,18 +184,18 @@ + } + // Paper end - BeaconEffectEvent - public static void playSound(Level level, BlockPos pos, SoundEvent sound) { - level.playSound(null, pos, sound, SoundSource.BLOCKS, 1.0F, 1.0F); -@@ -280,7 +_,7 @@ + public static void playSound(final Level level, final BlockPos worldPosition, final SoundEvent event) { + level.playSound(null, worldPosition, event, SoundSource.BLOCKS, 1.0F, 1.0F); +@@ -288,7 +_,7 @@ } - private static @Nullable Holder loadEffect(ValueInput input, String key) { -- return input.read(key, BuiltInRegistries.MOB_EFFECT.holderByNameCodec()).filter(VALID_EFFECTS::contains).orElse(null); -+ return input.read(key, BuiltInRegistries.MOB_EFFECT.holderByNameCodec()).orElse(null); // CraftBukkit - persist manually set non-default beacon effects (SPIGOT-3598) + private static @Nullable Holder loadEffect(final ValueInput input, final String field) { +- return input.read(field, BuiltInRegistries.MOB_EFFECT.holderByNameCodec()).filter(VALID_EFFECTS::contains).orElse(null); ++ return input.read(field, BuiltInRegistries.MOB_EFFECT.holderByNameCodec()).orElse(null); // CraftBukkit - persist manually set non-default beacon effects (SPIGOT-3598) } @Override -@@ -288,8 +_,10 @@ +@@ -296,8 +_,10 @@ super.loadAdditional(input); this.primaryPower = loadEffect(input, "primary_effect"); this.secondaryPower = loadEffect(input, "secondary_effect"); @@ -220,20 +206,20 @@ } @Override -@@ -300,6 +_,7 @@ +@@ -308,6 +_,7 @@ output.putInt("Levels", this.levels); output.storeNullable("CustomName", ComponentSerialization.CODEC, this.name); this.lockKey.addToTag(output); + output.putDouble(PAPER_RANGE_TAG, this.effectRange); // Paper - Custom beacon ranges } - public void setCustomName(@Nullable Component name) { -@@ -313,7 +_,7 @@ + public void setCustomName(final @Nullable Component name) { +@@ -321,7 +_,7 @@ @Override - public @Nullable AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { + public @Nullable AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { - if (this.lockKey.canUnlock(player)) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockLockCheckEvent(this, this.lockKey, this.getDisplayName(), player)) { // Paper - Call BlockLockCheckEvent - return new BeaconMenu(containerId, playerInventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())); + return new BeaconMenu(containerId, inventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())); } else { BaseContainerBlockEntity.sendChestLockedNotifications(this.getBlockPos().getCenter(), player, this.getDisplayName()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch index 0ee4679347a5..9e05c00cee64 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -85,6 +_,7 @@ +@@ -86,6 +_,7 @@ public static final int MIN_OCCUPATION_TICKS_NECTARLESS = 600; private List stored = Lists.newArrayList(); public @Nullable BlockPos savedFlowerPos; + public int maxBees = MAX_OCCUPANTS; // CraftBukkit - allow setting max amount of bees a hive can hold - public BeehiveBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.BEEHIVE, pos, blockState); -@@ -118,7 +_,7 @@ + public BeehiveBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.BEEHIVE, worldPosition, blockState); +@@ -119,7 +_,7 @@ } public boolean isFull() { @@ -16,33 +16,34 @@ + return this.stored.size() == this.maxBees; // CraftBukkit } - public void emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus) { -@@ -127,7 +_,7 @@ - for (Entity entity : list) { - if (entity instanceof Bee bee && player.position().distanceToSqr(entity.position()) <= 16.0) { + public void emptyAllLivingFromHive(final @Nullable Player player, final BlockState state, final BeehiveBlockEntity.BeeReleaseStatus releaseReason) { +@@ -128,7 +_,7 @@ + for (Entity released : releasedFromHive) { + if (released instanceof Bee bee && player.position().distanceToSqr(released.position()) <= 16.0) { if (!this.isSedated()) { - bee.setTarget(player); + bee.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit } else { bee.setStayOutOfHiveCountdown(400); } -@@ -137,8 +_,14 @@ +@@ -138,10 +_,15 @@ } - private List releaseAllOccupants(BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus) { + private List releaseAllOccupants(final BlockState state, final BeehiveBlockEntity.BeeReleaseStatus releaseStatus) { + // CraftBukkit start - This allows us to bypass the night/rain/emergency check + return this.releaseBees(state, releaseStatus, false); + } -+ -+ public List releaseBees(BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, boolean force) { -+ // CraftBukkit end - This allows us to bypass t he night/rain/emergecny check - List list = Lists.newArrayList(); -- this.stored.removeIf(data -> releaseOccupant(this.level, this.worldPosition, state, data.toOccupant(), list, releaseStatus, this.savedFlowerPos)); -+ this.stored.removeIf(data -> releaseOccupant(this.level, this.worldPosition, state, data.toOccupant(), list, releaseStatus, this.savedFlowerPos, force)); // CraftBukkit - This allows us to bypass t he night/rain/emergecny check - if (!list.isEmpty()) { ++ public List releaseBees(final BlockState state, final BeehiveBlockEntity.BeeReleaseStatus releaseStatus, final boolean force) { ++ // CraftBukkit end - This allows us to bypass the night/rain/emergency check + List spawned = Lists.newArrayList(); + this.stored + .removeIf( +- occupantEntry -> releaseOccupant(this.level, this.worldPosition, state, occupantEntry.toOccupant(), spawned, releaseStatus, this.savedFlowerPos) ++ occupantEntry -> releaseOccupant(this.level, this.worldPosition, state, occupantEntry.toOccupant(), spawned, releaseStatus, this.savedFlowerPos, force) // CraftBukkit - This allows us to bypass the night/rain/emergency check + ); + if (!spawned.isEmpty()) { super.setChanged(); - } -@@ -151,6 +_,11 @@ +@@ -155,6 +_,12 @@ return this.stored.size(); } @@ -51,13 +52,14 @@ + this.stored.clear(); + } + // Paper end - Add EntityBlockStorage clearEntities - public static int getHoneyLevel(BlockState state) { - return state.getValue(BeehiveBlock.HONEY_LEVEL); ++ + public static int getHoneyLevel(final BlockState blockState) { + return blockState.getValue(BeehiveBlock.HONEY_LEVEL); } -@@ -161,7 +_,16 @@ +@@ -165,7 +_,16 @@ } - public void addOccupant(Bee bee) { + public void addOccupant(final Bee bee) { - if (this.stored.size() < 3) { + if (this.stored.size() < this.maxBees) { // CraftBukkit + // CraftBukkit start @@ -72,7 +74,7 @@ bee.stopRiding(); bee.ejectPassengers(); bee.dropLeash(); -@@ -186,7 +_,7 @@ +@@ -190,7 +_,7 @@ this.level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(bee, this.getBlockState())); } @@ -81,99 +83,99 @@ super.setChanged(); } } -@@ -204,8 +_,21 @@ - BeehiveBlockEntity.BeeReleaseStatus releaseStatus, - @Nullable BlockPos storedFlowerPos - ) { -- if (level.environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, pos) -- && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { -+ // CraftBukkit start -+ return releaseOccupant(level, pos, state, occupant, storedInHives, releaseStatus, storedFlowerPos, false); +@@ -199,6 +_,12 @@ + this.stored.add(new BeehiveBlockEntity.BeeData(occupant)); + } + ++ // CraftBukkit start ++ private static boolean releaseOccupant(final Level level, final BlockPos blockPos, final BlockState state, final BeehiveBlockEntity.Occupant beeData, final @Nullable List spawned, final BeehiveBlockEntity.BeeReleaseStatus releaseStatus, final @Nullable BlockPos savedFlowerPos) { ++ return releaseOccupant(level, blockPos, state, beeData, spawned, releaseStatus, savedFlowerPos, false); + } -+ private static boolean releaseOccupant( -+ Level level, -+ BlockPos pos, -+ BlockState state, -+ BeehiveBlockEntity.Occupant occupant, -+ @Nullable List storedInHives, -+ BeehiveBlockEntity.BeeReleaseStatus releaseStatus, -+ @Nullable BlockPos storedFlowerPos, -+ boolean force -+ ) { -+ if (!force && level.environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, pos) && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { -+ // CraftBukkit end ++ // CraftBukkit end ++ + private static boolean releaseOccupant( + final Level level, + final BlockPos blockPos, +@@ -207,8 +_,9 @@ + final @Nullable List spawned, + final BeehiveBlockEntity.BeeReleaseStatus releaseStatus, + final @Nullable BlockPos savedFlowerPos ++ , final boolean force // CraftBukkit + ) { +- if (level.environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, blockPos) ++ if (!force && level.environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, blockPos) // CraftBukkit + && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { return false; } else { - Direction direction = state.getValue(BeehiveBlock.FACING); -@@ -216,6 +_,17 @@ +@@ -220,6 +_,17 @@ } else { - Entity entity = occupant.createEntity(level, pos); + Entity entity = beeData.createEntity(level, blockPos); if (entity != null) { + // CraftBukkit start + if (entity instanceof Bee) { + float bbWidth = entity.getBbWidth(); -+ double d = flag ? 0.0 : 0.55 + bbWidth / 2.0F; -+ double d1 = pos.getX() + 0.5 + d * direction.getStepX(); -+ double d2 = pos.getY() + 0.5 - entity.getBbHeight() / 2.0F; -+ double d3 = pos.getZ() + 0.5 + d * direction.getStepZ(); -+ entity.snapTo(d1, d2, d3, entity.getYRot(), entity.getXRot()); ++ double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; ++ double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); ++ double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; ++ double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); ++ entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); + } + if (!level.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below + // CraftBukkit end if (entity instanceof Bee bee) { - if (storedFlowerPos != null && !bee.hasSavedFlowerPos() && level.random.nextFloat() < 0.9F) { - bee.setSavedFlowerPos(storedFlowerPos); -@@ -231,7 +_,13 @@ - i--; + RandomSource random = level.getRandom(); + if (savedFlowerPos != null && !bee.hasSavedFlowerPos() && random.nextFloat() < 0.9F) { +@@ -236,7 +_,13 @@ + levelIncrease--; } -- level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + i)); +- level.setBlockAndUpdate(blockPos, state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease)); + // Paper start - Fire EntityChangeBlockEvent in more places -+ BlockState newBlockState = state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + i); ++ BlockState newBlockState = state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease); + -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, newBlockState)) { -+ level.setBlockAndUpdate(pos, newBlockState); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos, newBlockState)) { ++ level.setBlockAndUpdate(blockPos, newBlockState); + } + // Paper end - Fire EntityChangeBlockEvent in more places } } } -@@ -240,17 +_,19 @@ - storedInHives.add(bee); +@@ -245,17 +_,19 @@ + spawned.add(bee); } + /* CraftBukkit start - move up float bbWidth = entity.getBbWidth(); - double d = flag ? 0.0 : 0.55 + bbWidth / 2.0F; - double d1 = pos.getX() + 0.5 + d * direction.getStepX(); - double d2 = pos.getY() + 0.5 - entity.getBbHeight() / 2.0F; - double d3 = pos.getZ() + 0.5 + d * direction.getStepZ(); - entity.snapTo(d1, d2, d3, entity.getYRot(), entity.getXRot()); + double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; + double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); + double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; + double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); + entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); + */ // CraftBukkit end } - level.playSound(null, pos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, level.getBlockState(pos))); + level.playSound(null, blockPos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(entity, level.getBlockState(blockPos))); - return level.addFreshEntity(entity); + return true; // CraftBukkit - moved up } else { return false; } -@@ -276,6 +_,11 @@ - flag = true; +@@ -283,6 +_,11 @@ + changed = true; iterator.remove(); } + // Paper start - Fix bees aging inside; use exitTickCounter to keep actual bee life + else if (level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) { -+ beeData.exitTickCounter = beeData.occupant.minTicksInHive / 2; ++ data.exitTickCounter = data.occupant.minTicksInHive / 2; + } + // Paper end - Fix bees aging inside; use exitTickCounter to keep actual bee life } } -@@ -297,9 +_,10 @@ +@@ -304,9 +_,10 @@ @Override - protected void loadAdditional(ValueInput input) { + protected void loadAdditional(final ValueInput input) { super.loadAdditional(input); - this.stored.clear(); + this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change) @@ -183,7 +185,7 @@ } @Override -@@ -307,12 +_,13 @@ +@@ -314,12 +_,13 @@ super.saveAdditional(output); output.store("bees", BeehiveBlockEntity.Occupant.LIST_CODEC, this.getBees()); output.storeNullable("flower_pos", BlockPos.CODEC, this.savedFlowerPos); @@ -191,21 +193,21 @@ } @Override - protected void applyImplicitComponents(DataComponentGetter componentGetter) { - super.applyImplicitComponents(componentGetter); + protected void applyImplicitComponents(final DataComponentGetter components) { + super.applyImplicitComponents(components); - this.stored.clear(); + this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change) - List list = componentGetter.getOrDefault(DataComponents.BEES, Bees.EMPTY).bees(); - list.forEach(this::storeBee); + List bees = components.getOrDefault(DataComponents.BEES, Bees.EMPTY).bees(); + bees.forEach(this::storeBee); } -@@ -340,15 +_,18 @@ +@@ -347,15 +_,18 @@ - static class BeeData { + private static class BeeData { private final BeehiveBlockEntity.Occupant occupant; + private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts private int ticksInHive; - BeeData(BeehiveBlockEntity.Occupant occupant) { + private BeeData(final BeehiveBlockEntity.Occupant occupant) { this.occupant = occupant; this.ticksInHive = occupant.ticksInHive(); + this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives @@ -218,19 +220,3 @@ } public BeehiveBlockEntity.Occupant toOccupant() { -@@ -422,6 +_,7 @@ - } - - private static void setBeeReleaseData(int ticksInHive, Bee bee) { -+ if (!bee.ageLocked) { // Paper - Honor ageLock - int age = bee.getAge(); - if (age < 0) { - bee.setAge(Math.min(0, age + ticksInHive)); -@@ -430,6 +_,7 @@ - } - - bee.setInLoveTime(Math.max(0, bee.getInLoveTime() - ticksInHive)); -+ } // Paper - Honor ageLock - } - } - } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch index 810b2c47e5e5..dc9dcd3abff4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch @@ -1,26 +1,26 @@ --- a/net/minecraft/world/level/block/entity/BellBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BellBlockEntity.java -@@ -60,6 +_,11 @@ +@@ -62,6 +_,11 @@ - if (blockEntity.ticks >= 50) { - blockEntity.shaking = false; + if (entity.ticks >= 50) { + entity.shaking = false; + // Paper start - Fix bell block entity memory leak -+ if (!blockEntity.resonating) { -+ blockEntity.nearbyEntities.clear(); ++ if (!entity.resonating) { ++ entity.nearbyEntities.clear(); + } + // Paper end - Fix bell block entity memory leak - blockEntity.ticks = 0; + entity.ticks = 0; } -@@ -73,6 +_,7 @@ - blockEntity.resonationTicks++; +@@ -75,6 +_,7 @@ + entity.resonationTicks++; } else { - resonationEndAction.run(level, pos, blockEntity.nearbyEntities); -+ blockEntity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak - blockEntity.resonating = false; + onResonationEnd.run(level, pos, entity.nearbyEntities); ++ entity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak + entity.resonating = false; } } -@@ -113,6 +_,8 @@ +@@ -115,6 +_,8 @@ } } } @@ -28,33 +28,33 @@ + this.nearbyEntities.removeIf(e -> !e.isAlive()); // Paper - Fix bell block entity memory leak } - private static boolean areRaidersNearby(BlockPos pos, List raiders) { -@@ -129,7 +_,10 @@ + private static boolean areRaidersNearby(final BlockPos bellPos, final List nearbyEntities) { +@@ -128,7 +_,10 @@ } - private static void makeRaidersGlow(Level level, BlockPos pos, List raiders) { -- raiders.stream().filter(raider -> isRaiderWithinRange(pos, raider)).forEach(BellBlockEntity::glow); + private static void makeRaidersGlow(final Level level, final BlockPos blockPos, final List nearbyEntities) { +- nearbyEntities.stream().filter(e -> isRaiderWithinRange(blockPos, e)).forEach(BellBlockEntity::glow); + // Paper start - call bell resonate event and bell reveal raider event -+ final List inRangeRaiders = raiders.stream().filter(raider -> isRaiderWithinRange(pos, raider)).map(e -> (org.bukkit.entity.LivingEntity) e.getBukkitEntity()).toList(); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(level, pos, inRangeRaiders).forEach(e -> glow(e, pos)); ++ final List inRangeRaiders = nearbyEntities.stream().filter(e -> isRaiderWithinRange(blockPos, e)).map(e -> (org.bukkit.entity.LivingEntity) e.getBukkitEntity()).toList(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(level, blockPos, inRangeRaiders).forEach(e -> glow(e, blockPos)); + // Paper end - call bell resonate event and bell reveal raider event } - private static void showBellParticles(Level level, BlockPos pos, List raiders) { + private static void showBellParticles(final Level level, final BlockPos bellPos, final List nearbyEntities) { @@ -159,7 +_,16 @@ - return raider.isAlive() && !raider.isRemoved() && pos.closerToCenterThan(raider.position(), 48.0) && raider.getType().is(EntityTypeTags.RAIDERS); + return entity.isAlive() && !entity.isRemoved() && blockPos.closerToCenterThan(entity.position(), 48.0) && entity.is(EntityTypeTags.RAIDERS); } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add BellRevealRaiderEvent - private static void glow(LivingEntity entity) { + private static void glow(final LivingEntity raider) { + // Paper start - Add BellRevealRaiderEvent -+ glow(entity, null); ++ glow(raider, null); + } + -+ private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { -+ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) ++ private static void glow(LivingEntity raider, @org.jspecify.annotations.Nullable BlockPos pos) { ++ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(raider.level(), pos), (org.bukkit.entity.Raider) raider.getBukkitEntity()).callEvent()) + return; + // Paper end - Add BellRevealRaiderEvent - entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); + raider.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch index 4767a1f8501f..1d32cbf29e53 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -37,6 +_,10 @@ +@@ -40,6 +_,10 @@ import org.slf4j.Logger; - public abstract class BlockEntity implements DebugValueSource { + public abstract class BlockEntity implements DebugValueSource, TypedInstance> { + // CraftBukkit start - data containers + private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); + public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer; @@ -11,34 +11,39 @@ private static final Codec> TYPE_CODEC = BuiltInRegistries.BLOCK_ENTITY_TYPE.byNameCodec(); private static final Logger LOGGER = LogUtils.getLogger(); private final BlockEntityType type; -@@ -51,6 +_,7 @@ - this.worldPosition = pos.immutable(); +@@ -54,6 +_,7 @@ + this.worldPosition = worldPosition.immutable(); this.validateBlockState(blockState); this.blockState = blockState; + this.persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(DATA_TYPE_REGISTRY); // Paper - always init } - private void validateBlockState(BlockState state) { -@@ -67,6 +_,7 @@ - int intOr = tag.getIntOr("x", 0); - int intOr1 = tag.getIntOr("y", 0); - int intOr2 = tag.getIntOr("z", 0); -+ if (chunkPos != null) { // Paper - allow reading non-validated pos from tag - used to parse block entities on items - int sectionPosCoord = SectionPos.blockToSectionCoord(intOr); - int sectionPosCoord1 = SectionPos.blockToSectionCoord(intOr2); - if (sectionPosCoord != chunkPos.x || sectionPosCoord1 != chunkPos.z) { -@@ -74,6 +_,7 @@ - intOr = chunkPos.getBlockX(SectionPos.sectionRelative(intOr)); - intOr2 = chunkPos.getBlockZ(SectionPos.sectionRelative(intOr2)); + private void validateBlockState(final BlockState blockState) { +@@ -66,10 +_,11 @@ + return this.type.isValid(blockState); + } + +- public static BlockPos getPosFromTag(final ChunkPos base, final CompoundTag entityTag) { ++ public static BlockPos getPosFromTag(final @Nullable ChunkPos base, final CompoundTag entityTag) { // Paper - allow reading non-validated pos from tag - nullable + int x = entityTag.getIntOr("x", 0); + int y = entityTag.getIntOr("y", 0); + int z = entityTag.getIntOr("z", 0); ++ if (base != null) { // Paper - allow reading non-validated pos from tag - used to parse block entities on items + int sectionX = SectionPos.blockToSectionCoord(x); + int sectionZ = SectionPos.blockToSectionCoord(z); + if (sectionX != base.x() || sectionZ != base.z()) { +@@ -77,6 +_,7 @@ + x = base.getBlockX(SectionPos.sectionRelative(x)); + z = base.getBlockZ(SectionPos.sectionRelative(z)); } + } // Paper - allow reading non-validated pos from tag - used to parse block entities on items - return new BlockPos(intOr, intOr1, intOr2); + return new BlockPos(x, y, z); } -@@ -91,6 +_,12 @@ +@@ -94,6 +_,12 @@ } - protected void loadAdditional(ValueInput input) { + protected void loadAdditional(final ValueInput input) { + // Paper start - read persistent data container + this.persistentDataContainer.clear(); // Paper - clear instead of init + @@ -47,9 +52,9 @@ + // Paper end - read persistent data container } - public final void loadWithComponents(ValueInput input) { -@@ -140,6 +_,11 @@ - public void saveWithoutMetadata(ValueOutput output) { + public final void loadWithComponents(final ValueInput input) { +@@ -143,6 +_,11 @@ + public void saveWithoutMetadata(final ValueOutput output) { this.saveAdditional(output); output.store("components", DataComponentMap.CODEC, this.components); + // CraftBukkit start - store container @@ -59,10 +64,10 @@ + // CraftBukkit end } - public final CompoundTag saveCustomOnly(HolderLookup.Provider registries) { -@@ -155,6 +_,11 @@ + public final CompoundTag saveCustomOnly(final HolderLookup.Provider registries) { +@@ -158,6 +_,11 @@ - public void saveCustomOnly(ValueOutput output) { + public void saveCustomOnly(final ValueOutput output) { this.saveAdditional(output); + // Paper start - store PDC here as well + if (!this.persistentDataContainer.isEmpty()) { @@ -71,34 +76,34 @@ + // Paper end } - public void saveId(ValueOutput output) { -@@ -285,6 +_,12 @@ + public void saveId(final ValueOutput output) { +@@ -293,6 +_,12 @@ } - public final void applyComponents(DataComponentMap components, DataComponentPatch patch) { + public final void applyComponents(final DataComponentMap prototype, final DataComponentPatch patch) { + // CraftBukkit start -+ this.applyComponentsSet(components, patch); ++ this.applyComponentsSet(prototype, patch); + } + -+ public final Set> applyComponentsSet(DataComponentMap components, DataComponentPatch patch) { ++ public final Set> applyComponentsSet(final DataComponentMap prototype, final DataComponentPatch patch) { + // CraftBukkit end - final Set> set = new HashSet<>(); - set.add(DataComponents.BLOCK_ENTITY_DATA); - set.add(DataComponents.BLOCK_STATE); -@@ -304,6 +_,10 @@ + final Set> implicitComponents = new HashSet<>(); + implicitComponents.add(DataComponents.BLOCK_ENTITY_DATA); + implicitComponents.add(DataComponents.BLOCK_STATE); +@@ -316,6 +_,10 @@ }); - DataComponentPatch dataComponentPatch = patch.forget(set::contains); - this.components = dataComponentPatch.split().added(); + DataComponentPatch newPatch = patch.forget(implicitComponents::contains); + this.components = newPatch.split().added(); + // CraftBukkit start -+ set.remove(DataComponents.BLOCK_ENTITY_DATA); // Remove as never actually added by applyImplicitComponents -+ return set; ++ implicitComponents.remove(DataComponents.BLOCK_ENTITY_DATA); // Remove as never actually added by applyImplicitComponents ++ return implicitComponents; + // CraftBukkit end } - protected void collectImplicitComponents(DataComponentMap.Builder components) { -@@ -339,6 +_,27 @@ + protected void collectImplicitComponents(final DataComponentMap.Builder components) { +@@ -351,6 +_,27 @@ @Override - public void registerDebugValues(ServerLevel level, DebugValueSource.Registration registrar) { + public void registerDebugValues(final ServerLevel level, final DebugValueSource.Registration registration) { } + + // CraftBukkit start - add method @@ -122,5 +127,5 @@ + } + // Paper end - Sanitize sent data - record BlockEntityPathElement(BlockEntity blockEntity) implements ProblemReporter.PathElement { + private record BlockEntityPathElement(BlockEntity blockEntity) implements ProblemReporter.PathElement { @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch index a3402fa98d97..266d51acd6f3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -@@ -41,6 +_,7 @@ +@@ -43,6 +_,7 @@ private static final Component DEFAULT_NAME = Component.translatable("container.brewing"); private NonNullList items = NonNullList.withSize(5, ItemStack.EMPTY); public int brewTime; @@ -8,15 +8,15 @@ private boolean[] lastPotionCount; private Item ingredient; public int fuel; -@@ -50,6 +_,7 @@ - return switch (index) { +@@ -56,6 +_,7 @@ + return switch (dataId) { case 0 -> BrewingStandBlockEntity.this.brewTime; case 1 -> BrewingStandBlockEntity.this.fuel; + case 2 -> BrewingStandBlockEntity.this.recipeBrewTime; // Paper - Add recipeBrewTime default -> 0; }; } -@@ -62,14 +_,54 @@ +@@ -68,14 +_,54 @@ break; case 1: BrewingStandBlockEntity.this.fuel = value; @@ -70,73 +70,73 @@ + } + // CraftBukkit end - public BrewingStandBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.BREWING_STAND, pos, blockState); -@@ -98,8 +_,21 @@ - public static void serverTick(Level level, BlockPos pos, BlockState state, BrewingStandBlockEntity blockEntity) { - ItemStack itemStack = blockEntity.items.get(4); - if (blockEntity.fuel <= 0 && itemStack.is(ItemTags.BREWING_FUEL)) { -- blockEntity.fuel = 20; -- itemStack.shrink(1); + public BrewingStandBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.BREWING_STAND, worldPosition, blockState); +@@ -104,8 +_,21 @@ + public static void serverTick(final Level level, final BlockPos pos, final BlockState selfState, final BrewingStandBlockEntity entity) { + ItemStack fuel = entity.items.get(4); + if (entity.fuel <= 0 && fuel.is(ItemTags.BREWING_FUEL)) { +- entity.fuel = 20; +- fuel.shrink(1); + // CraftBukkit start + org.bukkit.event.inventory.BrewingStandFuelEvent event = new org.bukkit.event.inventory.BrewingStandFuelEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), -+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(fuel), + 20 + ); + if (!event.callEvent()) { + return; + } + -+ blockEntity.fuel = event.getFuelPower(); -+ if (blockEntity.fuel > 0 && event.isConsuming()) { -+ itemStack.shrink(1); ++ entity.fuel = event.getFuelPower(); ++ if (entity.fuel > 0 && event.isConsuming()) { ++ fuel.shrink(1); + } + // CraftBukkit end - setChanged(level, pos, state); + setChanged(level, pos, selfState); } -@@ -110,7 +_,7 @@ - blockEntity.brewTime--; - boolean flag1 = blockEntity.brewTime == 0; - if (flag1 && isBrewable) { -- doBrew(level, pos, blockEntity.items); -+ doBrew(level, pos, blockEntity.items, blockEntity); // CraftBukkit - } else if (!isBrewable || !itemStack1.is(blockEntity.ingredient)) { - blockEntity.brewTime = 0; +@@ -116,7 +_,7 @@ + entity.brewTime--; + boolean isDoneBrewing = entity.brewTime == 0; + if (isDoneBrewing && brewable) { +- doBrew(level, pos, entity.items); ++ doBrew(level, pos, entity.items, entity); // CraftBukkit + } else if (!brewable || !ingredient.is(entity.ingredient)) { + entity.brewTime = 0; } -@@ -118,7 +_,14 @@ - setChanged(level, pos, state); - } else if (isBrewable && blockEntity.fuel > 0) { - blockEntity.fuel--; -- blockEntity.brewTime = 400; +@@ -124,7 +_,14 @@ + setChanged(level, pos, selfState); + } else if (brewable && entity.fuel > 0) { + entity.fuel--; +- entity.brewTime = 400; + // CraftBukkit start + org.bukkit.event.block.BrewingStartEvent event = new org.bukkit.event.block.BrewingStartEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), -+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack1), 400); ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(ingredient), 400); + event.callEvent(); -+ blockEntity.recipeBrewTime = event.getRecipeBrewTime(); // Paper - use recipe brew time from event -+ blockEntity.brewTime = event.getBrewingTime(); // 400 -> event.getTotalBrewTime() // Paper - use brewing time from event ++ entity.recipeBrewTime = event.getRecipeBrewTime(); // Paper - use recipe brew time from event ++ entity.brewTime = event.getBrewingTime(); // 400 -> event.getTotalBrewTime() // Paper - use brewing time from event + // CraftBukkit end - blockEntity.ingredient = itemStack1.getItem(); - setChanged(level, pos, state); + entity.ingredient = ingredient.getItem(); + setChanged(level, pos, selfState); } -@@ -169,13 +_,37 @@ +@@ -175,13 +_,37 @@ } } -- private static void doBrew(Level level, BlockPos pos, NonNullList items) { -+ private static void doBrew(Level level, BlockPos pos, NonNullList items, BrewingStandBlockEntity brewingStandBlockEntity) { // CraftBukkit - ItemStack itemStack = items.get(3); +- private static void doBrew(final Level level, final BlockPos pos, final NonNullList items) { ++ private static void doBrew(final Level level, final BlockPos pos, final NonNullList items, final BrewingStandBlockEntity entity) { // CraftBukkit + ItemStack ingredient = items.get(3); PotionBrewing potionBrewing = level.potionBrewing(); + // CraftBukkit start -+ org.bukkit.inventory.InventoryHolder owner = brewingStandBlockEntity.getOwner(); ++ org.bukkit.inventory.InventoryHolder owner = entity.getOwner(); + java.util.List brewResults = new java.util.ArrayList<>(3); - for (int i = 0; i < 3; i++) { -- items.set(i, potionBrewing.mix(itemStack, items.get(i))); + for (int dest = 0; dest < 3; dest++) { +- items.set(dest, potionBrewing.mix(ingredient, items.get(dest))); - } -+ brewResults.add(i, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(potionBrewing.mix(itemStack, items.get(i)))); ++ brewResults.add(dest, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(potionBrewing.mix(ingredient, items.get(dest)))); + } + + if (owner != null) { @@ -144,37 +144,37 @@ + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), + (org.bukkit.inventory.BrewerInventory) owner.getInventory(), + brewResults, -+ brewingStandBlockEntity.fuel ++ entity.fuel + ); + if (!event.callEvent()) { + return; + } + -+ for (int i = 0; i < 3; i++) { -+ if (i < brewResults.size()) { -+ items.set(i, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(brewResults.get(i))); ++ for (int dest = 0; dest < 3; dest++) { ++ if (dest < brewResults.size()) { ++ items.set(dest, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(brewResults.get(dest))); + } else { -+ items.set(i, ItemStack.EMPTY); ++ items.set(dest, ItemStack.EMPTY); + } + } + } + // CraftBukkit end - itemStack.shrink(1); - ItemStack craftingRemainder = itemStack.getItem().getCraftingRemainder(); -@@ -214,13 +_,13 @@ + ingredient.shrink(1); + ItemStackTemplate remainder = ingredient.getItem().getCraftingRemainder(); +@@ -220,13 +_,13 @@ @Override - public boolean canPlaceItem(int index, ItemStack stack) { + public boolean canPlaceItem(final int slot, final ItemStack itemStack) { + PotionBrewing potionBrewing = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up - if (index == 3) { + if (slot == 3) { - PotionBrewing potionBrewing = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; - return potionBrewing.isIngredient(stack); + return potionBrewing.isIngredient(itemStack); } else { - return index == 4 - ? stack.is(ItemTags.BREWING_FUEL) -- : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) -+ : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack)) // Paper - Custom Potion Mixes - && this.getItem(index).isEmpty(); + return slot == 4 + ? itemStack.is(ItemTags.BREWING_FUEL) +- : (itemStack.is(Items.POTION) || itemStack.is(Items.SPLASH_POTION) || itemStack.is(Items.LINGERING_POTION) || itemStack.is(Items.GLASS_BOTTLE)) ++ : (itemStack.is(Items.POTION) || itemStack.is(Items.SPLASH_POTION) || itemStack.is(Items.LINGERING_POTION) || itemStack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(itemStack)) // Paper - Custom Potion Mixes + && this.getItem(slot).isEmpty(); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch index 9121a4882188..d3a465b684db 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/entity/BrushableBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BrushableBlockEntity.java -@@ -66,9 +_,26 @@ +@@ -67,9 +_,26 @@ return false; } else { - this.coolDownEndsAtTick = startTick + 10L; + this.coolDownEndsAtTick = gameTime + 10L; + // Paper start - EntityChangeBlockEvent + // The vanilla logic here is *so* backwards, we'd be moving basically *all* following calls down. + // Instead, compute vanilla ourselves up here and just replace the below usages with our computed values for a free diff-on-change. @@ -14,63 +14,65 @@ + final BlockState nextBrokenBlockState = this.getBlockState().setValue(BlockStateProperties.DUSTED, nextCompletionStage); + if (enoughBrushesToBreak || differentCompletionStages) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent( -+ brusher, this.worldPosition, enoughBrushesToBreak ? computeTurnsTo().defaultBlockState() : nextBrokenBlockState ++ user, this.worldPosition, enoughBrushesToBreak ? this.computeTurnsTo().defaultBlockState() : nextBrokenBlockState + )) { -+ brushCount--; ++ this.brushCount--; + return false; + } + } + // Paper end - EntityChangeBlockEvent - this.unpackLootTable(level, brusher, stack); -- int completionState = this.getCompletionState(); + this.unpackLootTable(level, user, brush); +- int previousCompletionState = this.getCompletionState(); - if (++this.brushCount >= 10) { -+ int completionState = currentCompletionStage; // Paper - EntityChangeBlockEvent - use precomputed - diff on change ++ int previousCompletionState = currentCompletionStage; // Paper - EntityChangeBlockEvent - use precomputed - diff on change + if (enoughBrushesToBreak) { // Paper - EntityChangeBlockEvent - use precomputed - diff on change - this.brushingCompleted(level, brusher, stack); + this.brushingCompleted(level, user, brush); return true; } else { -@@ -76,7 +_,7 @@ - int completionState1 = this.getCompletionState(); - if (completionState != completionState1) { - BlockState blockState = this.getBlockState(); -- BlockState blockState1 = blockState.setValue(BlockStateProperties.DUSTED, completionState1); -+ BlockState blockState1 = nextBrokenBlockState; // Paper - EntityChangeBlockEvent - use precomputed - diff on change - level.setBlock(this.getBlockPos(), blockState1, Block.UPDATE_ALL); +@@ -77,7 +_,7 @@ + int completionState = this.getCompletionState(); + if (previousCompletionState != completionState) { + BlockState previousState = this.getBlockState(); +- BlockState state = previousState.setValue(BlockStateProperties.DUSTED, completionState); ++ BlockState state = nextBrokenBlockState; // Paper - EntityChangeBlockEvent - use precomputed - diff on change + level.setBlock(this.getBlockPos(), state, Block.UPDATE_ALL); } -@@ -117,6 +_,11 @@ - this.dropContent(level, brusher, stack); +@@ -118,6 +_,12 @@ + this.dropContent(level, user, brush); BlockState blockState = this.getBlockState(); level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_BRUSH_BLOCK_COMPLETE, this.getBlockPos(), Block.getId(blockState)); + // Paper start - EntityChangeEvent - extract result block logic + this.brushingCompleteUpdateBlock(this.computeTurnsTo()); + } ++ + private Block computeTurnsTo() { + // Paper end - EntityChangeEvent - extract result block logic Block turnsInto; if (this.getBlockState().getBlock() instanceof BrushableBlock brushableBlock) { turnsInto = brushableBlock.getTurnsInto(); -@@ -124,6 +_,11 @@ +@@ -125,6 +_,12 @@ turnsInto = Blocks.AIR; } + // Paper start - EntityChangeEvent - extract result block logic + return turnsInto; + } ++ + public void brushingCompleteUpdateBlock(final Block turnsInto) { + // Paper end - EntityChangeEvent - extract result block logic level.setBlock(this.worldPosition, turnsInto.defaultBlockState(), Block.UPDATE_ALL); } -@@ -140,7 +_,12 @@ - double d5 = blockPos.getZ() + 0.5 * d1 + d2; - ItemEntity itemEntity = new ItemEntity(level, d3, d4, d5, this.item.split(level.random.nextInt(21) + 10)); - itemEntity.setDeltaMovement(Vec3.ZERO); -- level.addFreshEntity(itemEntity); +@@ -141,7 +_,12 @@ + double zo = dropPos.getZ() + 0.5 * centerRange + halfSize; + ItemEntity entity = new ItemEntity(level, xo, yo, zo, this.item.split(level.getRandom().nextInt(21) + 10)); + entity.setDeltaMovement(Vec3.ZERO); +- level.addFreshEntity(entity); + // CraftBukkit start -+ if (brusher instanceof final ServerPlayer serverPlayer) { ++ if (user instanceof final ServerPlayer serverPlayer) { + org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bblock.getState(), serverPlayer, java.util.List.of(itemEntity)); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bblock.getState(), serverPlayer, java.util.List.of(entity)); + } + // CraftBukkit end this.item = ItemStack.EMPTY; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch index f86a822e5e36..991f89beb316 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java -@@ -20,6 +_,12 @@ +@@ -21,6 +_,12 @@ public VibrationSystem.User createVibrationUser() { return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos()); } @@ -12,8 +12,8 @@ + // Paper end - Configurable sculk sensor listener range protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser { - public VibrationUser(final BlockPos blockPos1) { -@@ -28,6 +_,7 @@ + public VibrationUser(final BlockPos blockPos) { +@@ -30,6 +_,7 @@ @Override public int getListenerRadius() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch index b55ef3a0b745..b22ba8ff3bdf 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch @@ -6,58 +6,56 @@ public final int[] cookingTime = new int[4]; + public final boolean[] stopCooking = new boolean[4]; // Paper - Add more Campfire API - public CampfireBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.CAMPFIRE, pos, blockState); -@@ -64,14 +_,44 @@ - ItemStack itemStack = campfire.items.get(i); + public CampfireBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.CAMPFIRE, worldPosition, blockState); +@@ -64,12 +_,42 @@ + ItemStack itemStack = entity.items.get(slot); if (!itemStack.isEmpty()) { - flag = true; -+ if (!campfire.stopCooking[i]) { // Paper - Add more Campfire API - campfire.cookingProgress[i]++; + changed = true; ++ if (!entity.stopCooking[slot]) { // Paper - Add more Campfire API + entity.cookingProgress[slot]++; + } // Paper - Add more Campfire API - if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) { - SingleRecipeInput singleRecipeInput = new SingleRecipeInput(itemStack); -- ItemStack itemStack1 = check.getRecipeFor(singleRecipeInput, level) + if (entity.cookingProgress[slot] >= entity.cookingTime[slot]) { + SingleRecipeInput input = new SingleRecipeInput(itemStack); +- ItemStack result = recipeCache.getRecipeFor(input, level).map(r -> r.value().assemble(input)).orElse(itemStack); + // Paper start - add recipe to cook events -+ final var optionalCookingRecipe = check.getRecipeFor(singleRecipeInput, level); -+ ItemStack itemStack1 = optionalCookingRecipe - .map(recipe -> recipe.value().assemble(singleRecipeInput, level.registryAccess())) - .orElse(itemStack); ++ final java.util.Optional> recipe = recipeCache.getRecipeFor(input, level); ++ ItemStack result = recipe.map(r -> r.value().assemble(input)).orElse(itemStack); + // Paper end - add recipe to cook events - if (itemStack1.isItemEnabled(level.enabledFeatures())) { -- Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack1); + if (result.isItemEnabled(level.enabledFeatures())) { +- Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), result); + // CraftBukkit start - fire BlockCookEvent + org.bukkit.craftbukkit.inventory.CraftItemStack source = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); -+ org.bukkit.inventory.ItemStack result = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemStack1); ++ org.bukkit.inventory.ItemStack apiResult = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(result); + + org.bukkit.event.block.BlockCookEvent blockCookEvent = new org.bukkit.event.block.BlockCookEvent( + org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), + source, -+ result, -+ (org.bukkit.inventory.CookingRecipe) optionalCookingRecipe.map(RecipeHolder::toBukkitRecipe).orElse(null) // Paper -Add recipe to cook events ++ apiResult, ++ (org.bukkit.inventory.CookingRecipe) recipe.map(RecipeHolder::toBukkitRecipe).orElse(null) // Paper - Add recipe to cook events + ); + + if (!blockCookEvent.callEvent()) { + return; + } + -+ result = blockCookEvent.getResult(); -+ itemStack1 = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(result); ++ apiResult = blockCookEvent.getResult(); ++ result = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(apiResult); + // CraftBukkit end + // Paper start - Fix item locations dropped from campfires + double deviation = 0.05F * RandomSource.GAUSSIAN_SPREAD_FACTOR; -+ while (!itemStack1.isEmpty()) { -+ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(level, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemStack1.split(level.random.nextInt(21) + 10)); -+ droppedItem.setDeltaMovement(level.random.triangle(0.0D, deviation), level.random.triangle(0.2D, deviation), level.random.triangle(0.0D, deviation)); ++ while (!result.isEmpty()) { ++ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, result.split(level.getRandom().nextInt(21) + 10)); ++ droppedItem.setDeltaMovement(level.getRandom().triangle(0.0, deviation), level.getRandom().triangle(0.2, deviation), level.getRandom().triangle(0.0, deviation)); + level.addFreshEntity(droppedItem); + } + // Paper end - Fix item locations dropped from campfires - campfire.items.set(i, ItemStack.EMPTY); + entity.items.set(slot, ItemStack.EMPTY); level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); -@@ -143,6 +_,16 @@ - .ifPresentOrElse( - ints -> System.arraycopy(ints, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, ints.length)), () -> Arrays.fill(this.cookingTime, 0) +@@ -142,6 +_,16 @@ + cookingTimes -> System.arraycopy(cookingTimes, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, cookingTimes.length)), + () -> Arrays.fill(this.cookingTime, 0) ); + + // Paper start - Add more Campfire API @@ -72,7 +70,7 @@ } @Override -@@ -151,6 +_,13 @@ +@@ -150,6 +_,13 @@ ContainerHelper.saveAllItems(output, this.items, true); output.putIntArray("CookingTimes", this.cookingProgress); output.putIntArray("CookingTotalTimes", this.cookingTime); @@ -86,20 +84,20 @@ } @Override -@@ -180,7 +_,15 @@ +@@ -179,7 +_,15 @@ return false; } -- this.cookingTime[i] = recipeFor.get().value().cookingTime(); +- this.cookingTime[slot] = recipe.get().value().cookingTime(); + // CraftBukkit start + org.bukkit.event.block.CampfireStartEvent event = new org.bukkit.event.block.CampfireStartEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(this.level,this.worldPosition), -+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), -+ (org.bukkit.inventory.CampfireRecipe) recipeFor.get().toBukkitRecipe() ++ org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition), ++ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(placeItem), ++ (org.bukkit.inventory.CampfireRecipe) recipe.get().toBukkitRecipe() + ); -+ this.level.getCraftServer().getPluginManager().callEvent(event); -+ this.cookingTime[i] = event.getTotalCookTime(); // i -> event.getTotalCookTime() ++ event.callEvent(); ++ this.cookingTime[slot] = event.getTotalCookTime(); // recipe.get().value().cookingTime() -> event.getTotalCookTime() + // CraftBukkit end - this.cookingProgress[i] = 0; - this.items.set(i, stack.consumeAndReturn(1, entity)); - level.gameEvent(GameEvent.BLOCK_CHANGE, this.getBlockPos(), GameEvent.Context.of(entity, this.getBlockState())); + this.cookingProgress[slot] = 0; + this.items.set(slot, placeItem.consumeAndReturn(1, sourceEntity)); + serverLevel.gameEvent(GameEvent.BLOCK_CHANGE, this.getBlockPos(), GameEvent.Context.of(sourceEntity, this.getBlockState())); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch index 7bda53a37e0c..5a386c38181c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java +++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -62,6 +_,40 @@ +@@ -67,6 +_,40 @@ }; private final ChestLidController chestLidController = new ChestLidController(); @@ -38,6 +38,6 @@ + } + // CraftBukkit end + - protected ChestBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { - super(type, pos, blockState); + protected ChestBlockEntity(final BlockEntityType type, final BlockPos worldPosition, final BlockState blockState) { + super(type, worldPosition, blockState); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch index b9714df750b2..5cd1132dcad6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch @@ -34,14 +34,14 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.Location getLocation() { ++ public org.bukkit.@org.jspecify.annotations.Nullable Location getLocation() { + if (this.level == null) return null; + return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.worldPosition, this.level); + } + // CraftBukkit end + - public ChiseledBookShelfBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.CHISELED_BOOKSHELF, pos, blockState); + public ChiseledBookShelfBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.CHISELED_BOOKSHELF, worldPosition, blockState); } @@ -68,7 +_,7 @@ @@ -53,20 +53,20 @@ @Override @@ -81,7 +_,7 @@ - ItemStack itemStack = Objects.requireNonNullElse(this.getItems().get(slot), ItemStack.EMPTY); + ItemStack retrievedItem = Objects.requireNonNullElse(this.getItems().get(slot), ItemStack.EMPTY); this.getItems().set(slot, ItemStack.EMPTY); - if (!itemStack.isEmpty()) { + if (!retrievedItem.isEmpty()) { - this.updateState(slot); + if (this.level != null) this.updateState(slot); // CraftBukkit - SPIGOT-7381: check for null world } - return itemStack; + return retrievedItem; @@ -91,7 +_,7 @@ - public void setItem(int slot, ItemStack stack) { - if (this.acceptsItemType(stack)) { - this.getItems().set(slot, stack); + public void setItem(final int slot, final ItemStack itemStack) { + if (this.acceptsItemType(itemStack)) { + this.getItems().set(slot, itemStack); - this.updateState(slot); + if (this.level != null) this.updateState(slot); // CraftBukkit - SPIGOT-7381: check for null world - } else if (stack.isEmpty()) { + } else if (itemStack.isEmpty()) { this.removeItem(slot, this.getMaxStackSize()); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch index aaa4eb961a99..15397f883fde 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/entity/CommandBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CommandBlockEntity.java -@@ -27,6 +_,18 @@ - private boolean auto = false; - private boolean conditionMet = false; - private final BaseCommandBlock commandBlock = new BaseCommandBlock() { +@@ -32,6 +_,18 @@ + Objects.requireNonNull(CommandBlockEntity.this); + } + + // CraftBukkit start + @Override + public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) { @@ -17,11 +17,11 @@ + // CraftBukkit end + @Override - public void setCommand(String command) { + public void setCommand(final String command) { super.setCommand(command); -@@ -47,7 +_,7 @@ +@@ -52,7 +_,7 @@ Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), - new Vec2(0.0F, direction.toYRot()), + new Vec2(0.0F, facing.toYRot()), level, - LevelBasedPermissionSet.GAMEMASTER, + LevelBasedPermissionSet.forLevel(net.minecraft.server.permissions.PermissionLevel.byId(level.paperConfig().commandBlocks.permissionsLevel)), // Paper - configurable command block perm level diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch index da783a5a8b1d..f10559537eed 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch @@ -3,50 +3,52 @@ @@ -164,8 +_,20 @@ } - private static void applyEffects(Level level, BlockPos pos, List positions) { + private static void applyEffects(final Level level, final BlockPos worldPosition, final List effectBlocks) { + // CraftBukkit start -+ ConduitBlockEntity.applyEffects(level, pos, ConduitBlockEntity.getRange(positions)); ++ ConduitBlockEntity.applyEffects(level, worldPosition, ConduitBlockEntity.getRange(effectBlocks)); + } + -+ public static int getRange(List positions) { ++ public static int getRange(List effectBlocks) { + // CraftBukkit end - int size = positions.size(); - int i = size / 7 * 16; + int activeSize = effectBlocks.size(); + int effectRange = activeSize / 7 * 16; + // CraftBukkit start -+ return i; ++ return effectRange; + } + -+ private static void applyEffects(Level level, BlockPos pos, int i) { // i = effect range in blocks ++ private static void applyEffects(Level level, BlockPos worldPosition, int effectRange) { // i = effect range in blocks + // CraftBukkit end - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); -@@ -174,20 +_,25 @@ - if (!entitiesOfClass.isEmpty()) { - for (Player player : entitiesOfClass) { - if (pos.closerThan(player.blockPosition(), i) && player.isInWaterOrRain()) { + int x = worldPosition.getX(); + int y = worldPosition.getY(); + int z = worldPosition.getZ(); +@@ -174,7 +_,7 @@ + if (!players.isEmpty()) { + for (Player player : players) { + if (worldPosition.closerThan(player.blockPosition(), effectRange) && player.isInWaterOrRain()) { - player.addEffect(new MobEffectInstance(MobEffects.CONDUIT_POWER, 260, 0, true, true)); + player.addEffect(new MobEffectInstance(MobEffects.CONDUIT_POWER, 260, 0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONDUIT); // CraftBukkit } } } - } - - private static void updateAndAttackTarget(ServerLevel level, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity, boolean canDestroy) { -+ // CraftBukkit start - add "damageTarget" boolean -+ updateAndAttackTarget(level, pos, state, blockEntity, canDestroy, true); +@@ -183,13 +_,19 @@ + private static void updateAndAttackTarget( + final ServerLevel level, final BlockPos worldPosition, final BlockState blockState, final ConduitBlockEntity entity, final boolean isActive + ) { ++ // CraftBukkit start - add "damageTarget" boolean ++ updateAndAttackTarget(level, worldPosition, blockState, entity, isActive, true); + } -+ public static void updateAndAttackTarget(ServerLevel level, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity, boolean canDestroy, boolean damageTarget) { -+ // CraftBukkit end - add "damageTarget" boolean - EntityReference entityReference = updateDestroyTarget(blockEntity.destroyTarget, level, pos, canDestroy); - LivingEntity livingEntity = EntityReference.getLivingEntity(entityReference, level); -- if (livingEntity != null) { -+ if (damageTarget && livingEntity != null) { // CraftBukkit -+ if (livingEntity.hurtServer(level, level.damageSources().magic().eventBlockDamager(level, pos), 4.0F)) // CraftBukkit - move up ++ ++ public static void updateAndAttackTarget(ServerLevel level, BlockPos worldPosition, BlockState blockState, ConduitBlockEntity entity, boolean isActive, boolean damageTarget) { ++ // CraftBukkit end - add "damageTarget" boolean + EntityReference newDestroyTarget = updateDestroyTarget(entity.destroyTarget, level, worldPosition, isActive); + LivingEntity targetEntity = EntityReference.getLivingEntity(newDestroyTarget, level); +- if (targetEntity != null) { ++ if (damageTarget && targetEntity != null) { // CraftBukkit ++ if (targetEntity.hurtServer(level, level.damageSources().magic().eventBlockDamager(level, worldPosition), 4.0F)) // CraftBukkit - move up level.playSound( - null, livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F + null, targetEntity.getX(), targetEntity.getY(), targetEntity.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F ); -- livingEntity.hurtServer(level, level.damageSources().magic(), 4.0F); +- targetEntity.hurtServer(level, level.damageSources().magic(), 4.0F); } - if (!Objects.equals(entityReference, blockEntity.destroyTarget)) { + if (!Objects.equals(newDestroyTarget, entity.destroyTarget)) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java.patch index 6d5d58c6b485..2256d543153f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java.patch @@ -6,27 +6,27 @@ private double maxInteractionRange; + // CraftBukkit start + public boolean opened; -+ public void onAPIOpen(Level level, BlockPos blockPos, BlockState blockState) { -+ this.onOpen(level, blockPos, blockState); ++ public void onOpenAPI(Level level, BlockPos pos, BlockState blockState) { ++ this.onOpen(level, pos, blockState); + } + -+ public void onAPIClose(Level level, BlockPos blockPos, BlockState blockState) { -+ this.onClose(level, blockPos, blockState); ++ public void onCloseAPI(Level level, BlockPos pos, BlockState blockState) { ++ this.onClose(level, pos, blockState); + } + -+ public void openerAPICountChanged(Level level, BlockPos blockPos, BlockState blockState, int count, int openCount) { -+ this.openerCountChanged(level, blockPos, blockState, count, openCount); ++ public void openerCountChangedAPI(Level level, BlockPos pos, BlockState blockState, int previous, int current) { ++ this.openerCountChanged(level, pos, blockState, previous, current); + } + // CraftBukkit end - protected abstract void onOpen(Level level, BlockPos pos, BlockState state); + protected abstract void onOpen(final Level level, final BlockPos pos, final BlockState blockState); -@@ -26,7 +_,19 @@ - public abstract boolean isOwnContainer(Player player); - - public void incrementOpeners(LivingEntity entity, Level level, BlockPos pos, BlockState state, double interactionRange) { +@@ -28,7 +_,19 @@ + public void incrementOpeners( + final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState, final double maxInteractionRange + ) { + int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added - int i = this.openCount++; + int previous = this.openCount++; + + // CraftBukkit start - Call redstone event + if (level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) { @@ -38,16 +38,16 @@ + } + // CraftBukkit end + - if (i == 0) { - this.onOpen(level, pos, state); + if (previous == 0) { + this.onOpen(level, pos, blockState); level.gameEvent(entity, GameEvent.CONTAINER_OPEN, pos); -@@ -38,7 +_,20 @@ +@@ -40,7 +_,20 @@ } - public void decrementOpeners(LivingEntity entity, Level level, BlockPos pos, BlockState state) { + public void decrementOpeners(final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState) { + int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added + if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative - int i = this.openCount--; + int previous = this.openCount--; + + // CraftBukkit start - Call redstone event + if (level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) { @@ -60,13 +60,13 @@ + // CraftBukkit end + if (this.openCount == 0) { - this.onClose(level, pos, state); + this.onClose(level, pos, blockState); level.gameEvent(entity, GameEvent.CONTAINER_CLOSE, pos); -@@ -70,6 +_,7 @@ +@@ -74,6 +_,7 @@ } - int size = entitiesWithContainerOpen.size(); -+ if (this.opened) size++; // CraftBukkit - add dummy count from API - int i = this.openCount; - if (i != size) { - boolean flag = size != 0; + int openCount = containerUsers.size(); ++ if (this.opened) openCount++; // CraftBukkit - add dummy count from API + int prevCount = this.openCount; + if (prevCount != openCount) { + boolean isOpen = openCount != 0; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch index 14acb4180199..a312097f3c11 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/CrafterBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CrafterBlockEntity.java -@@ -60,6 +_,47 @@ +@@ -67,6 +_,47 @@ } }; @@ -39,12 +39,12 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.Location getLocation() { ++ public org.bukkit.@org.jspecify.annotations.Nullable Location getLocation() { + if (this.level == null) return null; + return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.worldPosition, this.level); + } + // CraftBukkit end + - public CrafterBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.CRAFTER, pos, blockState); + public CrafterBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.CRAFTER, worldPosition, blockState); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java.patch index a9db73b06478..2a1439c3eb58 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java @@ -110,7 +_,7 @@ - if (creakingHeart.creakingInfo == null) { - if (blockState.getValue(CreakingHeartBlock.STATE) == CreakingHeartState.AWAKE) { + if (entity.creakingInfo == null) { + if (updatedState.getValue(CreakingHeartBlock.STATE) == CreakingHeartState.AWAKE) { if (serverLevel.isSpawningMonsters()) { -- Player nearestPlayer = level.getNearestPlayer(pos.getX(), pos.getY(), pos.getZ(), 32.0, false); -+ Player nearestPlayer = level.getNearestPlayerThatAffectsSpawning(pos.getX(), pos.getY(), pos.getZ(), 32.0, false); // Paper - Affects Spawning API - if (nearestPlayer != null) { - Creaking creaking = spawnProtector(serverLevel, creakingHeart); +- Player player = level.getNearestPlayer(pos.getX(), pos.getY(), pos.getZ(), 32.0, false); ++ Player player = level.getNearestPlayerThatAffectsSpawning(pos.getX(), pos.getY(), pos.getZ(), 32.0, false); // Paper - Affects Spawning API + if (player != null) { + Creaking creaking = spawnProtector(serverLevel, entity); if (creaking != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java.patch index 6e186effe97c..74e44965dbbc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java +++ b/net/minecraft/world/level/block/entity/DecoratedPotBlockEntity.java -@@ -23,6 +_,48 @@ +@@ -25,6 +_,48 @@ import org.jspecify.annotations.Nullable; - public class DecoratedPotBlockEntity extends BlockEntity implements RandomizableContainer, ContainerSingleItem.BlockContainerSingleItem { + public class DecoratedPotBlockEntity extends BlockEntity implements ContainerSingleItem.BlockContainerSingleItem, RandomizableContainer { + + // CraftBukkit start - add fields and methods + public List transaction = new java.util.ArrayList<>(); @@ -49,7 +49,7 @@ public static final String TAG_SHERDS = "sherds"; public static final String TAG_ITEM = "item"; public static final int EVENT_POT_WOBBLES = 1; -@@ -45,8 +_,8 @@ +@@ -47,8 +_,8 @@ output.store("sherds", PotDecorations.CODEC, this.decorations); } @@ -60,10 +60,10 @@ } } -@@ -68,7 +_,14 @@ +@@ -70,7 +_,14 @@ @Override - public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + public CompoundTag getUpdateTag(final HolderLookup.Provider registries) { - return this.saveCustomOnly(registries); + // Paper start - hide unnecessary update data + // Like chests, decorated pots should not allow clients to inspect their contents without breaking them. diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/DispenserBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/DispenserBlockEntity.java.patch index 50aa6814a631..5864a5c95b24 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/DispenserBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/DispenserBlockEntity.java.patch @@ -39,6 +39,6 @@ + } + // CraftBukkit end + - protected DispenserBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { - super(type, pos, blockState); + protected DispenserBlockEntity(final BlockEntityType type, final BlockPos worldPosition, final BlockState blockState) { + super(type, worldPosition, blockState); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch index b6f64612fd73..bb2bc131a7fc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch @@ -38,105 +38,103 @@ + } + // CraftBukkit end + - public HopperBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.HOPPER, pos, blockState); + public HopperBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.HOPPER, worldPosition, blockState); this.facing = blockState.getValue(HopperBlock.FACING); -@@ -99,7 +_,14 @@ - blockEntity.tickedGameTime = level.getGameTime(); - if (!blockEntity.isOnCooldown()) { - blockEntity.setCooldown(0); -- tryMoveItems(level, pos, state, blockEntity, () -> suckInItems(level, blockEntity)); +@@ -99,7 +_,12 @@ + entity.tickedGameTime = level.getGameTime(); + if (!entity.isOnCooldown()) { + entity.setCooldown(0); +- tryMoveItems(level, pos, state, entity, () -> suckInItems(level, entity)); + // Spigot start -+ boolean result = tryMoveItems(level, pos, state, blockEntity, () -> { -+ return suckInItems(level, blockEntity); -+ }); -+ if (!result && blockEntity.level.spigotConfig.hopperCheck > 1) { -+ blockEntity.setCooldown(blockEntity.level.spigotConfig.hopperCheck); ++ boolean result = tryMoveItems(level, pos, state, entity, () -> suckInItems(level, entity)); ++ if (!result && entity.level.spigotConfig.hopperCheck > 1) { ++ entity.setCooldown(entity.level.spigotConfig.hopperCheck); + } + // Spigot end } } -@@ -118,7 +_,7 @@ +@@ -120,7 +_,7 @@ } - if (flag) { -- blockEntity.setCooldown(8); -+ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot + if (changed) { +- entity.setCooldown(8); ++ entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot setChanged(level, pos, state); return true; } -@@ -151,14 +_,47 @@ - ItemStack item = blockEntity.getItem(i); - if (!item.isEmpty()) { - int count = item.getCount(); -- ItemStack itemStack = addItem(blockEntity, attachedContainer, blockEntity.removeItem(i, 1), opposite); +@@ -153,14 +_,47 @@ + ItemStack itemStack = self.getItem(slot); + if (!itemStack.isEmpty()) { + int originalCount = itemStack.getCount(); +- ItemStack result = addItem(self, container, self.removeItem(slot, 1), direction); + // CraftBukkit start - Call event when pushing items into other inventories -+ ItemStack original = item.copy(); ++ ItemStack original = itemStack.copy(); + org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( -+ blockEntity.removeItem(i, level.spigotConfig.hopperAmount) ++ self.removeItem(slot, level.spigotConfig.hopperAmount) + ); // Spigot + + org.bukkit.inventory.Inventory destinationInventory; + // Have to special case large chests as they work oddly -+ if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) { ++ if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) { + destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); -+ } else if (attachedContainer.getOwner() != null) { -+ destinationInventory = attachedContainer.getOwner().getInventory(); ++ } else if (container.getOwner() != null) { ++ destinationInventory = container.getOwner().getInventory(); + } else { -+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer); ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container); + } + + org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( -+ blockEntity.getOwner().getInventory(), ++ self.getOwner().getInventory(), + oitemstack, + destinationInventory, + true + ); + if (!event.callEvent()) { -+ blockEntity.setItem(i, original); -+ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot ++ self.setItem(slot, original); ++ self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot + return false; + } + int origCount = event.getItem().getAmount(); // Spigot -+ ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite); ++ ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction); + // CraftBukkit end + - if (itemStack.isEmpty()) { - attachedContainer.setChanged(); + if (result.isEmpty()) { + container.setChanged(); return true; } - item.setCount(count); -- if (count == 1) { + itemStack.setCount(originalCount); +- if (originalCount == 1) { + // Spigot start -+ item.shrink(origCount - itemStack.getCount()); -+ if (count <= level.spigotConfig.hopperAmount) { ++ itemStack.shrink(origCount - result.getCount()); ++ if (originalCount <= level.spigotConfig.hopperAmount) { + // Spigot end - blockEntity.setItem(i, item); + self.setItem(slot, itemStack); } } -@@ -221,7 +_,7 @@ +@@ -223,7 +_,7 @@ Direction direction = Direction.DOWN; - for (int i : getSlots(sourceContainer, direction)) { -- if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction)) { -+ if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot + for (int slot : getSlots(container, direction)) { +- if (tryTakeInItemFromSlot(hopper, container, slot, direction)) { ++ if (tryTakeInItemFromSlot(hopper, container, slot, direction, level)) { // Spigot return true; } } -@@ -241,18 +_,56 @@ +@@ -245,18 +_,55 @@ } } -- private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction) { -+ private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot - ItemStack item = container.getItem(slot); - if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) { - int count = item.getCount(); -- ItemStack itemStack = addItem(container, hopper, container.removeItem(slot, 1), null); +- private static boolean tryTakeInItemFromSlot(final Hopper hopper, final Container container, final int slot, final Direction direction) { ++ private static boolean tryTakeInItemFromSlot(final Hopper hopper, final Container container, final int slot, final Direction direction, final Level level) { // Spigot + ItemStack itemStack = container.getItem(slot); + if (!itemStack.isEmpty() && canTakeItemFromContainer(hopper, container, itemStack, slot, direction)) { + int originalCount = itemStack.getCount(); +- ItemStack result = addItem(container, hopper, container.removeItem(slot, 1), null); + // CraftBukkit start - Call event on collection of items from inventories into the hopper -+ ItemStack original = item.copy(); ++ ItemStack original = itemStack.copy(); + org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( + container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot + ); @@ -168,79 +166,79 @@ + return false; + } + int origCount = event.getItem().getAmount(); // Spigot -+ ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null); ++ ItemStack result = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null); + // CraftBukkit end -+ - if (itemStack.isEmpty()) { + if (result.isEmpty()) { container.setChanged(); return true; } - item.setCount(count); -- if (count == 1) { + itemStack.setCount(originalCount); +- if (originalCount == 1) { + // Spigot start -+ item.shrink(origCount - itemStack.getCount()); -+ if (count <= level.spigotConfig.hopperAmount) { ++ itemStack.shrink(origCount - result.getCount()); ++ if (originalCount <= level.spigotConfig.hopperAmount) { + // Spigot end - container.setItem(slot, item); + container.setItem(slot, itemStack); } } -@@ -262,12 +_,20 @@ +@@ -266,12 +_,20 @@ - public static boolean addItem(Container container, ItemEntity item) { - boolean flag = false; + public static boolean addItem(final Container container, final ItemEntity entity) { + boolean changed = false; + // CraftBukkit start + org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent( -+ container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity() ++ container.getOwner().getInventory(), (org.bukkit.entity.Item) entity.getBukkitEntity() + ); + if (!event.callEvent()) { + return false; + } + // CraftBukkit end - ItemStack itemStack = item.getItem().copy(); - ItemStack itemStack1 = addItem(null, container, itemStack, null); - if (itemStack1.isEmpty()) { - flag = true; - item.setItem(ItemStack.EMPTY); -- item.discard(); -+ item.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + ItemStack copy = entity.getItem().copy(); + ItemStack result = addItem(null, container, copy, null); + if (result.isEmpty()) { + changed = true; + entity.setItem(ItemStack.EMPTY); +- entity.discard(); ++ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause } else { - item.setItem(itemStack1); + entity.setItem(result); } -@@ -309,11 +_,18 @@ - boolean flag = false; - boolean isEmpty = destination.isEmpty(); - if (item.isEmpty()) { +@@ -317,11 +_,18 @@ + boolean success = false; + boolean wasEmpty = container.isEmpty(); + if (current.isEmpty()) { + // Spigot start - SPIGOT-6693, SimpleContainer#setItem + ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size -+ if (!stack.isEmpty() && stack.getCount() > destination.getMaxStackSize()) { -+ leftover = stack; // Paper - Make hoppers respect inventory max stack size -+ stack = stack.split(destination.getMaxStackSize()); ++ if (!itemStack.isEmpty() && itemStack.getCount() > container.getMaxStackSize()) { ++ leftover = itemStack; // Paper - Make hoppers respect inventory max stack size ++ itemStack = itemStack.split(container.getMaxStackSize()); + } + // Spigot end - destination.setItem(slot, stack); -- stack = ItemStack.EMPTY; -+ stack = leftover; // Paper - Make hoppers respect inventory max stack size - flag = true; - } else if (canMergeItems(item, stack)) { -- int i = stack.getMaxStackSize() - item.getCount(); -+ int i = Math.min(stack.getMaxStackSize(), destination.getMaxStackSize()) - item.getCount(); // Paper - Make hoppers respect inventory max stack size - int min = Math.min(stack.getCount(), i); - stack.shrink(min); - item.grow(min); -@@ -327,7 +_,7 @@ - min = 1; + container.setItem(slot, itemStack); +- itemStack = ItemStack.EMPTY; ++ itemStack = leftover; // Paper - Make hoppers respect inventory max stack size + success = true; + } else if (canMergeItems(current, itemStack)) { +- int space = itemStack.getMaxStackSize() - current.getCount(); ++ int space = Math.min(itemStack.getMaxStackSize(), container.getMaxStackSize()) - current.getCount(); // Paper - Make hoppers respect inventory max stack size + int count = Math.min(itemStack.getCount(), space); + itemStack.shrink(count); + current.grow(count); +@@ -335,7 +_,7 @@ + skipTickCount = 1; } -- hopperBlockEntity.setCooldown(8 - min); -+ hopperBlockEntity.setCooldown(hopperBlockEntity.level.spigotConfig.hopperTransfer - min); // Spigot +- hopperBlockEntity.setCooldown(8 - skipTickCount); ++ hopperBlockEntity.setCooldown(hopperBlockEntity.level.spigotConfig.hopperTransfer - skipTickCount); // Spigot } - destination.setChanged(); -@@ -337,12 +_,56 @@ - return stack; - } + container.setChanged(); +@@ -344,13 +_,57 @@ + return itemStack; + } ++ + // CraftBukkit start + private static @Nullable Container runHopperInventorySearchEvent( + Container container, @@ -258,15 +256,15 @@ + return (event.getInventory() != null) ? ((org.bukkit.craftbukkit.inventory.CraftInventory) event.getInventory()).getInventory() : null; + } + // CraftBukkit end -+ - private static @Nullable Container getAttachedContainer(Level level, BlockPos pos, HopperBlockEntity blockEntity) { -- return getContainerAt(level, pos.relative(blockEntity.facing)); + + private static @Nullable Container getAttachedContainer(final Level level, final BlockPos blockPos, final HopperBlockEntity self) { +- return getContainerAt(level, blockPos.relative(self.facing)); + // Paper start -+ BlockPos searchPosition = pos.relative(blockEntity.facing); ++ BlockPos searchPosition = blockPos.relative(self.facing); + Container inventory = getContainerAt(level, searchPosition); + if (org.bukkit.event.inventory.HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) return inventory; + -+ org.bukkit.craftbukkit.block.CraftBlock hopper = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ org.bukkit.craftbukkit.block.CraftBlock hopper = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos); + org.bukkit.craftbukkit.block.CraftBlock searchBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, searchPosition); + return HopperBlockEntity.runHopperInventorySearchEvent( + inventory, @@ -277,10 +275,10 @@ + // Paper end } - private static @Nullable Container getSourceContainer(Level level, Hopper hopper, BlockPos pos, BlockState state) { + private static @Nullable Container getSourceContainer(final Level level, final Hopper hopper, final BlockPos pos, final BlockState state) { - return getContainerAt(level, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0, hopper.getLevelZ()); + // Paper start -+ final Container inventory = HopperBlockEntity.getContainerAt(level, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ()); ++ final Container inventory = HopperBlockEntity.getContainerAt(level, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0, hopper.getLevelZ()); + if (org.bukkit.event.inventory.HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) return inventory; + + final BlockPos hopperPos = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY(), hopper.getLevelZ()); @@ -295,11 +293,11 @@ + // Paper end } - public static List getItemsAtAndAbove(Level level, Hopper hopper) { -@@ -364,6 +_,7 @@ + public static List getItemsAtAndAbove(final Level level, final Hopper hopper) { +@@ -374,6 +_,7 @@ } - private static @Nullable Container getBlockContainer(Level level, BlockPos pos, BlockState state) { + private static @Nullable Container getBlockContainer(final Level level, final BlockPos pos, final BlockState state) { + if (!level.spigotConfig.hopperCanLoadChunks && !level.hasChunkAt(pos)) return null; // Spigot Block block = state.getBlock(); if (block instanceof WorldlyContainerHolder) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/JigsawBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/JigsawBlockEntity.java.patch index 489b7dec1443..6d6aa3f05104 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/JigsawBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/JigsawBlockEntity.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/block/entity/JigsawBlockEntity.java +++ b/net/minecraft/world/level/block/entity/JigsawBlockEntity.java @@ -140,7 +_,12 @@ - public void generate(ServerLevel level, int maxDepth, boolean keepJigsaws) { - BlockPos blockPos = this.getBlockPos().relative(this.getBlockState().getValue(JigsawBlock.ORIENTATION).front()); - Registry registry = level.registryAccess().lookupOrThrow(Registries.TEMPLATE_POOL); -- Holder orThrow = registry.getOrThrow(this.pool); + public void generate(final ServerLevel level, final int levels, final boolean keepJigsaws) { + BlockPos position = this.getBlockPos().relative(this.getBlockState().getValue(JigsawBlock.ORIENTATION).front()); + Registry poolRegistry = level.registryAccess().lookupOrThrow(Registries.TEMPLATE_POOL); +- Holder pool = poolRegistry.getOrThrow(this.pool); + // Paper start - Replace getHolderOrThrow with a null check -+ Holder orThrow = registry.get(this.pool).orElse(null); -+ if (orThrow == null) { ++ Holder pool = poolRegistry.get(this.pool).orElse(null); ++ if (pool == null) { + return; + } + // Paper end - Replace getHolderOrThrow with a null check - JigsawPlacement.generateJigsaw(level, orThrow, this.target, maxDepth, blockPos, keepJigsaws); + JigsawPlacement.generateJigsaw(level, pool, this.target, levels, position, keepJigsaws); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java.patch index 004ae297513a..3ef3b38b10b1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java.patch @@ -36,7 +36,7 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.Location getLocation() { ++ public org.bukkit.@org.jspecify.annotations.Nullable Location getLocation() { + if (this.level == null) return null; + return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.worldPosition, this.level); + } @@ -54,19 +54,17 @@ } @Override -@@ -157,11 +_,16 @@ +@@ -157,10 +_,15 @@ } @VisibleForTesting -- public void setSongItemWithoutPlaying(ItemStack stack) { -+ public void setSongItemWithoutPlaying(ItemStack stack, final long ticksSinceSongStarted) { // CraftBukkit - passed ticks since song started - this.item = stack; -- JukeboxSong.fromStack(this.level.registryAccess(), stack) -- .ifPresent(holder -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder)holder, 0L)); +- public void setSongItemWithoutPlaying(final ItemStack itemStack) { ++ public void setSongItemWithoutPlaying(final ItemStack itemStack, final long ticksSinceSongStarted) { // CraftBukkit - passed ticks since song started + this.item = itemStack; +- JukeboxSong.fromStack(itemStack).ifPresent(song -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder)song, 0L)); - this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock()); + this.jukeboxSongPlayer.song = null; // CraftBukkit - reset -+ JukeboxSong.fromStack(this.level != null ? this.level.registryAccess() : org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry(), stack) // Paper - fallback to other RegistryAccess if no level -+ .ifPresent(holder -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder)holder, ticksSinceSongStarted)); // CraftBukkit - passed ticks since song started ++ JukeboxSong.fromStack(itemStack).ifPresent(song -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder)song, ticksSinceSongStarted)); // CraftBukkit - passed ticks since song started + // CraftBukkit start - add null check for level + if (this.level != null) { + this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch index d6f544105f2a..8715b52b205d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/LecternBlockEntity.java +++ b/net/minecraft/world/level/block/entity/LecternBlockEntity.java -@@ -34,7 +_,53 @@ +@@ -36,11 +_,56 @@ public static final int NUM_DATA = 1; public static final int SLOT_BOOK = 0; public static final int NUM_SLOTS = 1; @@ -8,6 +8,10 @@ + // CraftBukkit start - add fields and methods + public final Container bookAccess = new LecternInventory(); + public class LecternInventory implements Container { + { + Objects.requireNonNull(LecternBlockEntity.this); + } + + public java.util.List transaction = new java.util.ArrayList<>(); + private int maxStack = 1; + @@ -51,17 +55,16 @@ + return LecternBlockEntity.this; + } + // CraftBukkit end -+ @Override public int getContainerSize() { return 1; -@@ -78,11 +_,19 @@ +@@ -84,11 +_,19 @@ @Override - public void setItem(int slot, ItemStack stack) { + public void setItem(final int slot, final ItemStack itemStack) { + // CraftBukkit start + if (slot == 0) { -+ LecternBlockEntity.this.setBook(stack); ++ LecternBlockEntity.this.setBook(itemStack); + if (LecternBlockEntity.this.getLevel() != null) { + LecternBlock.resetBookState(null, LecternBlockEntity.this.getLevel(), LecternBlockEntity.this.getBlockPos(), LecternBlockEntity.this.getBlockState(), LecternBlockEntity.this.hasBook()); + } @@ -76,17 +79,17 @@ } @Override -@@ -160,7 +_,7 @@ - if (i != this.page) { - this.page = i; +@@ -170,7 +_,7 @@ + if (newPage != this.page) { + this.page = newPage; this.setChanged(); - LecternBlock.signalPageChange(this.getLevel(), this.getBlockPos(), this.getBlockState()); + if (this.level != null) LecternBlock.signalPageChange(this.getLevel(), this.getBlockPos(), this.getBlockState()); // CraftBukkit } } -@@ -181,6 +_,36 @@ - return stack; +@@ -192,6 +_,36 @@ + return book; } + // CraftBukkit start @@ -119,24 +122,24 @@ + } + }; + // CraftBukkit end - private CommandSourceStack createCommandSourceStack(@Nullable Player player, ServerLevel level) { - String string; - Component component; -@@ -194,7 +_,7 @@ + private CommandSourceStack createCommandSourceStack(final @Nullable Player player, final ServerLevel level) { + String textName; + Component displayName; +@@ -205,7 +_,7 @@ - Vec3 vec3 = Vec3.atCenterOf(this.worldPosition); + Vec3 pos = Vec3.atCenterOf(this.worldPosition); return new CommandSourceStack( -- CommandSource.NULL, vec3, Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, string, component, level.getServer(), player -+ this.commandSource, vec3, Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, string, component, level.getServer(), player // CraftBukkit - commandSource +- CommandSource.NULL, pos, Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, textName, displayName, level.getServer(), player ++ this.commandSource, pos, Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, textName, displayName, level.getServer(), player // CraftBukkit - commandSource ); } -@@ -235,7 +_,7 @@ +@@ -246,7 +_,7 @@ @Override - public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { + public AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { - return new LecternMenu(containerId, this.bookAccess, this.dataAccess); -+ return new LecternMenu(containerId, this.bookAccess, this.dataAccess, playerInventory); // CraftBukkit ++ return new LecternMenu(containerId, this.bookAccess, this.dataAccess, inventory); // CraftBukkit } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java.patch index 587d8177a4e8..796a821f5366 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -@@ -114,4 +_,13 @@ +@@ -117,4 +_,13 @@ output.discard("LootTable"); output.discard("LootTableSeed"); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch index 27421fe52fed..377d19029cee 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java @@ -35,8 +_,18 @@ - this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(blockState, new BlockPositionSource(pos)); + this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(blockState, new BlockPositionSource(worldPosition)); } + // Paper start - Fix NPE in SculkBloomEvent world access @@ -12,9 +12,9 @@ + } + // Paper end - Fix NPE in SculkBloomEvent world access + - public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = sculkCatalyst.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. - sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true); + public static void serverTick(final Level level, final BlockPos pos, final BlockState state, final SculkCatalystBlockEntity entity) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = entity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. + entity.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true); + org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch index aa3908f8b08e..cbe5a9a1731f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java -@@ -21,6 +_,7 @@ +@@ -22,6 +_,7 @@ private final VibrationSystem.Listener vibrationListener; private final VibrationSystem.User vibrationUser; public int lastVibrationFrequency = 0; + @Nullable public Integer rangeOverride = null; // Paper - Configurable sculk sensor listener range - protected SculkSensorBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { - super(type, pos, blockState); -@@ -42,14 +_,22 @@ + protected SculkSensorBlockEntity(final BlockEntityType type, final BlockPos worldPosition, final BlockState blockState) { + super(type, worldPosition, blockState); +@@ -43,14 +_,22 @@ super.loadAdditional(input); this.lastVibrationFrequency = input.getIntOr("last_vibration_frequency", 0); this.vibrationData = input.read("listener", VibrationSystem.Data.CODEC).orElseGet(VibrationSystem.Data::new); @@ -17,7 +17,7 @@ + protected static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper - Configurable sculk sensor listener range @Override - protected void saveAdditional(ValueOutput output) { + protected void saveAdditional(final ValueOutput output) { super.saveAdditional(output); output.putInt("last_vibration_frequency", this.lastVibrationFrequency); output.store("listener", VibrationSystem.Data.CODEC, this.vibrationData); @@ -32,7 +32,7 @@ @Override public VibrationSystem.Data getVibrationData() { -@@ -86,6 +_,7 @@ +@@ -89,6 +_,7 @@ @Override public int getListenerRadius() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch index 1079d36b8d11..8bdd7e75a099 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java -@@ -87,6 +_,13 @@ +@@ -89,6 +_,13 @@ } - public static @Nullable ServerPlayer tryGetPlayer(@Nullable Entity entity) { + public static @Nullable ServerPlayer tryGetPlayer(final @Nullable Entity sourceEntity) { + // Paper start - check global player list where appropriate; ensure level is the same for sculk events -+ final ServerPlayer player = tryGetPlayer0(entity); -+ return player != null && player.level() == entity.level() ? player : null; ++ final ServerPlayer player = tryGetPlayer0(sourceEntity); ++ return player != null && sourceEntity != null && player.level() == sourceEntity.level() ? player : null; + } + @Nullable -+ private static ServerPlayer tryGetPlayer0(@Nullable Entity entity) { ++ private static ServerPlayer tryGetPlayer0(final @Nullable Entity sourceEntity) { + // Paper end - check global player list where appropriate - if (entity instanceof ServerPlayer serverPlayer) { - return serverPlayer; - } else if (entity != null && entity.getControllingPassenger() instanceof ServerPlayer serverPlayer) { -@@ -162,7 +_,7 @@ - private boolean trySummonWarden(ServerLevel level) { + if (sourceEntity instanceof ServerPlayer player) { + return player; + } else if (sourceEntity != null && sourceEntity.getControllingPassenger() instanceof ServerPlayer player) { +@@ -165,7 +_,7 @@ + private boolean trySummonWarden(final ServerLevel level) { return this.warningLevel >= 4 && SpawnUtil.trySpawnMob( - EntityType.WARDEN, EntitySpawnReason.TRIGGERED, level, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, false diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShelfBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShelfBlockEntity.java.patch index ca4946a67577..c070757f53da 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShelfBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShelfBlockEntity.java.patch @@ -39,12 +39,12 @@ + } + + @Override -+ public @javax.annotation.Nullable org.bukkit.Location getLocation() { ++ public org.bukkit.@Nullable Location getLocation() { + if (this.level == null) return null; + return org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.worldPosition, this.level); + } + // CraftBukkit end + - public ShelfBlockEntity(BlockPos pos, BlockState blockState) { - super(BlockEntityType.SHELF, pos, blockState); + public ShelfBlockEntity(final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.SHELF, worldPosition, blockState); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java.patch index 28174a42b059..5e0eb33688b7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java.patch @@ -40,8 +40,8 @@ + } + // CraftBukkit end + - public ShulkerBoxBlockEntity(@Nullable DyeColor color, BlockPos pos, BlockState blockState) { - super(BlockEntityType.SHULKER_BOX, pos, blockState); + public ShulkerBoxBlockEntity(final @Nullable DyeColor color, final BlockPos worldPosition, final BlockState blockState) { + super(BlockEntityType.SHULKER_BOX, worldPosition, blockState); this.color = color; @@ -171,6 +_,7 @@ } @@ -50,12 +50,12 @@ + if (this.opened) return; // CraftBukkit - only animate if the ShulkerBox hasn't been forced open already by an API call this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount); if (this.openCount == 1) { - this.level.gameEvent(user.getLivingEntity(), GameEvent.CONTAINER_OPEN, this.worldPosition); -@@ -184,6 +_,7 @@ - public void stopOpen(ContainerUser user) { - if (!this.remove && !user.getLivingEntity().isSpectator()) { + this.level.gameEvent(containerUser.getLivingEntity(), GameEvent.CONTAINER_OPEN, this.worldPosition); +@@ -186,6 +_,7 @@ + public void stopOpen(final ContainerUser containerUser) { + if (!this.remove && !containerUser.getLivingEntity().isSpectator()) { this.openCount--; + if (this.opened) return; // CraftBukkit - only animate if the ShulkerBox hasn't been forced open already by an API call. this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount); if (this.openCount <= 0) { - this.level.gameEvent(user.getLivingEntity(), GameEvent.CONTAINER_CLOSE, this.worldPosition); + this.level.gameEvent(containerUser.getLivingEntity(), GameEvent.CONTAINER_CLOSE, this.worldPosition); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch index 68c8a7c0eaaf..719a70f6d376 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/world/level/block/entity/SignBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SignBlockEntity.java -@@ -58,10 +_,15 @@ +@@ -59,10 +_,15 @@ } - public boolean isFacingFrontText(Player player) { + public boolean isFacingFrontText(final Player player) { + // Paper start - More Sign Block API + return this.isFacingFrontText(player.getX(), player.getZ()); + } -+ public boolean isFacingFrontText(double x, double z) { ++ public boolean isFacingFrontText(final double x, final double z) { + // Paper end - More Sign Block API - if (this.getBlockState().getBlock() instanceof SignBlock signBlock) { - Vec3 signHitboxCenterPosition = signBlock.getSignHitboxCenterPosition(this.getBlockState()); -- double d = player.getX() - (this.getBlockPos().getX() + signHitboxCenterPosition.x); -- double d1 = player.getZ() - (this.getBlockPos().getZ() + signHitboxCenterPosition.z); -+ double d = x - (this.getBlockPos().getX() + signHitboxCenterPosition.x); // Paper - More Sign Block API -+ double d1 = z - (this.getBlockPos().getZ() + signHitboxCenterPosition.z); // Paper - More Sign Block AP - float yRotationDegrees = signBlock.getYRotationDegrees(this.getBlockState()); - float f = (float)(Mth.atan2(d1, d) * 180.0F / (float)Math.PI) - 90.0F; - return Mth.degreesDifferenceAbs(yRotationDegrees, f) <= 90.0F; -@@ -129,11 +_,13 @@ + if (this.getBlockState().getBlock() instanceof SignBlock sign) { + Vec3 signPositionOffset = sign.getSignHitboxCenterPosition(this.getBlockState()); +- double xd = player.getX() - (this.getBlockPos().getX() + signPositionOffset.x); +- double zd = player.getZ() - (this.getBlockPos().getZ() + signPositionOffset.z); ++ double xd = x - (this.getBlockPos().getX() + signPositionOffset.x); // Paper - More Sign Block API ++ double zd = z - (this.getBlockPos().getZ() + signPositionOffset.z); // Paper - More Sign Block API + float signYRot = sign.getYRotationDegrees(this.getBlockState()); + float playerYRot = (float)(Mth.atan2(zd, xd) * 180.0F / (float)Math.PI) - 90.0F; + return Mth.degreesDifferenceAbs(signYRot, playerYRot) <= 90.0F; +@@ -130,11 +_,13 @@ - public void updateSignText(Player player, boolean isFrontText, List filteredText) { + public void updateSignText(final Player player, final boolean frontText, final List lines) { if (!this.isWaxed() && player.getUUID().equals(this.getPlayerWhoMayEdit()) && this.level != null) { -- this.updateText(signText -> this.setMessages(player, filteredText, signText), isFrontText); -+ this.updateText(signText -> this.setMessages(player, filteredText, signText, isFrontText), isFrontText); // CraftBukkit +- this.updateText(text -> this.setMessages(player, lines, text), frontText); ++ this.updateText(text -> this.setMessages(player, lines, text, frontText), frontText); // CraftBukkit this.setAllowedPlayerEditor(null); this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), Block.UPDATE_ALL); } else { @@ -33,43 +33,43 @@ } } -@@ -142,19 +_,41 @@ - return this.setText(updater.apply(text), isFrontText); +@@ -143,19 +_,41 @@ + return this.setText(function.apply(text), isFrontText); } -- private SignText setMessages(Player player, List filteredText, SignText text) { -+ private SignText setMessages(Player player, List filteredText, SignText text, boolean front) { // CraftBukkit +- private SignText setMessages(final Player player, final List lines, SignText text) { ++ private SignText setMessages(final Player player, final List lines, SignText text, final boolean front) { // CraftBukkit + SignText originalText = text; // CraftBukkit - for (int i = 0; i < filteredText.size(); i++) { - FilteredText filteredText1 = filteredText.get(i); - Style style = text.getMessage(i, player.isTextFilteringEnabled()).getStyle(); + for (int i = 0; i < lines.size(); i++) { + FilteredText line = lines.get(i); + Style currentTextStyle = text.getMessage(i, player.isTextFilteringEnabled()).getStyle(); if (player.isTextFilteringEnabled()) { -- text = text.setMessage(i, Component.literal(filteredText1.filteredOrEmpty()).setStyle(style)); -+ text = text.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style)); // Paper - filter sign text to chat only +- text = text.setMessage(i, Component.literal(line.filteredOrEmpty()).setStyle(currentTextStyle)); ++ text = text.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(line.filteredOrEmpty())).setStyle(currentTextStyle)); // Paper - filter sign text to chat only } else { text = text.setMessage( -- i, Component.literal(filteredText1.raw()).setStyle(style), Component.literal(filteredText1.filteredOrEmpty()).setStyle(style) -+ i, Component.literal(filteredText1.raw()).setStyle(style), Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style) // Paper - filter sign text to chat only +- i, Component.literal(line.raw()).setStyle(currentTextStyle), Component.literal(line.filteredOrEmpty()).setStyle(currentTextStyle) ++ i, Component.literal(line.raw()).setStyle(currentTextStyle), Component.literal(net.minecraft.util.StringUtil.filterText(line.filteredOrEmpty())).setStyle(currentTextStyle) // Paper - filter sign text to chat only ); } } + // CraftBukkit start + org.bukkit.entity.Player apiPlayer = ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(); -+ List lines = new java.util.ArrayList<>(); // Paper - adventure ++ List componentLines = new java.util.ArrayList<>(); // Paper - adventure + -+ for (int i = 0; i < filteredText.size(); ++i) { -+ lines.add(io.papermc.paper.adventure.PaperAdventure.asAdventure(text.getMessage(i, player.isTextFilteringEnabled()))); // Paper - Adventure ++ for (int i = 0; i < lines.size(); ++i) { ++ componentLines.add(io.papermc.paper.adventure.PaperAdventure.asAdventure(text.getMessage(i, player.isTextFilteringEnabled()))); // Paper - Adventure + } + -+ org.bukkit.event.block.SignChangeEvent event = new org.bukkit.event.block.SignChangeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition), apiPlayer, new java.util.ArrayList<>(lines), (front) ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK); // Paper - Adventure ++ org.bukkit.event.block.SignChangeEvent event = new org.bukkit.event.block.SignChangeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition), apiPlayer, new java.util.ArrayList<>(componentLines), (front) ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK); // Paper - Adventure + if (!event.callEvent()) { + return originalText; + } + + Component[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.lines()); // Paper - Adventure + for (int i = 0; i < components.length; i++) { -+ if (!java.util.Objects.equals(lines.get(i), event.line(i))) { // Paper - Adventure ++ if (!java.util.Objects.equals(componentLines.get(i), event.line(i))) { // Paper - Adventure + text = text.setMessage(i, components[i]); + } + } @@ -78,19 +78,19 @@ return text; } -@@ -193,7 +_,23 @@ - Style style = component.getStyle(); +@@ -194,7 +_,23 @@ + Style style = message.getStyle(); switch (style.getClickEvent()) { - case ClickEvent.RunCommand runCommand: -- level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(player, level, pos), runCommand.command()); + case ClickEvent.RunCommand command: +- level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(player, level, pos), command.command()); + // Paper start - Fix commands from signs not firing command events -+ String command = runCommand.command().startsWith("/") ? runCommand.command() : "/" + runCommand.command(); ++ String commandLine = command.command().startsWith("/") ? command.command() : "/" + command.command(); + if (org.spigotmc.SpigotConfig.logCommands) { -+ LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command); ++ LOGGER.info("{} issued server command: {}", player.getScoreboardName(), commandLine); + } + io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent( + (org.bukkit.entity.Player) player.getBukkitEntity(), -+ command, ++ commandLine, + new org.bukkit.craftbukkit.util.LazyPlayerSet(level.getServer()), + (org.bukkit.block.Sign) org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition).getState(), + isFrontText ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK @@ -100,14 +100,14 @@ + } + level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle(), level, pos), event.getMessage()); + // Paper end - Fix commands from signs not firing command events - flag = true; + hasAnyClickCommand = true; break; - case ClickEvent.ShowDialog showDialog: -@@ -212,12 +_,55 @@ - return flag; + case ClickEvent.ShowDialog dialog: +@@ -213,11 +_,55 @@ + return hasAnyClickCommand; } -- private static CommandSourceStack createCommandSourceStack(@Nullable Player player, ServerLevel level, BlockPos pos) { +- private static CommandSourceStack createCommandSourceStack(final @Nullable Player player, final ServerLevel level, final BlockPos pos) { + // CraftBukkit start + private final CommandSource commandSource = new CommandSource() { + @@ -135,14 +135,10 @@ + } + }; + -+ private CommandSourceStack createCommandSourceStack(@Nullable Player player, ServerLevel level, BlockPos pos) { ++ private CommandSourceStack createCommandSourceStack(final @Nullable Player player, final ServerLevel level, final BlockPos pos) { + // CraftBukkit end - String string = player == null ? "Sign" : player.getPlainTextName(); - Component component = (Component)(player == null ? Component.literal("Sign") : player.getDisplayName()); -- return new CommandSourceStack( -- CommandSource.NULL, Vec3.atCenterOf(pos), Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, string, component, level.getServer(), player -- ); -+ + String textName = player == null ? "Sign" : player.getPlainTextName(); + Component displayName = (Component)(player == null ? Component.literal("Sign") : player.getDisplayName()); + // Paper start - Fix commands from signs not firing command events + CommandSource commandSource = level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this.commandSource) { + @Override @@ -159,11 +155,13 @@ + } : this.commandSource; + // Paper end - Fix commands from signs not firing command events + // CraftBukkit - this -+ return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, string, component, level.getServer(), player); // Paper - Fix commands from signs not firing command events + return new CommandSourceStack( +- CommandSource.NULL, Vec3.atCenterOf(pos), Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, textName, displayName, level.getServer(), player ++ commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, level, LevelBasedPermissionSet.GAMEMASTER, textName, displayName, level.getServer(), player // Paper - Fix commands from signs not firing command events + ); } - @Override -@@ -235,12 +_,17 @@ +@@ -236,12 +_,17 @@ } public @Nullable UUID getPlayerWhoMayEdit() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestBlockEntity.java.patch index b515c4ea496c..d322861d25fc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestBlockEntity.java.patch @@ -3,7 +3,7 @@ @@ -38,6 +_,7 @@ @Override - protected void loadAdditional(ValueInput input) { + protected void loadAdditional(final ValueInput input) { + super.loadAdditional(input); // Paper - load the PDC this.mode = input.read("mode", TestBlockMode.CODEC).orElse(TestBlockMode.FAIL); this.message = input.getStringOr("message", ""); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java.patch index f6bbb048d83e..5654b523a96f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java +++ b/net/minecraft/world/level/block/entity/TestInstanceBlockEntity.java -@@ -157,6 +_,7 @@ +@@ -163,6 +_,7 @@ @Override - protected void loadAdditional(ValueInput input) { + protected void loadAdditional(final ValueInput input) { + super.loadAdditional(input); // Paper - load the PDC input.read("data", TestInstanceBlockEntity.Data.CODEC).ifPresent(this::set); this.errorMarkers.clear(); this.errorMarkers.addAll(input.read("errors", TestInstanceBlockEntity.ErrorMarker.LIST_CODEC).orElse(List.of())); -@@ -329,7 +_,7 @@ +@@ -343,7 +_,7 @@ } private void removeEntities() { -- this.level.getEntities(null, this.getStructureBounds()).stream().filter(entity -> !(entity instanceof Player)).forEach(Entity::discard); -+ this.level.getEntities(null, this.getStructureBounds()).stream().filter(entity -> !(entity instanceof Player)).forEach((entity) -> entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper +- this.level.getEntities(null, this.getTestBounds()).stream().filter(entity -> !(entity instanceof Player)).forEach(Entity::discard); ++ this.level.getEntities(null, this.getTestBounds()).stream().filter(entity -> !(entity instanceof Player)).forEach((entity) -> entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD)); // Paper } private void forceLoadChunks() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch index c9cd6f58f8f0..18b4f318b5c7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch @@ -3,9 +3,9 @@ @@ -129,7 +_,7 @@ } - public @Nullable Vec3 getPortalPosition(ServerLevel level, BlockPos pos) { -- if (this.exitPortal == null && level.dimension() == Level.END) { -+ if (this.exitPortal == null && level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END) { // CraftBukkit - work in alternate worlds - BlockPos blockPos = findOrCreateValidTeleportPos(level, pos); - blockPos = blockPos.above(10); - LOGGER.debug("Creating portal at {}", blockPos); + public @Nullable Vec3 getPortalPosition(final ServerLevel currentLevel, final BlockPos portalEntryPos) { +- if (this.exitPortal == null && currentLevel.dimension() == Level.END) { ++ if (this.exitPortal == null && currentLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END) { // CraftBukkit - work in alternate worlds + BlockPos exitPortalPos = findOrCreateValidTeleportPos(currentLevel, portalEntryPos); + exitPortalPos = exitPortalPos.above(10); + LOGGER.debug("Creating portal at {}", exitPortalPos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/PlayerDetector.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/PlayerDetector.java.patch index d67916b09b0a..406af683d0a3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/PlayerDetector.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/PlayerDetector.java.patch @@ -3,9 +3,9 @@ @@ -22,7 +_,7 @@ public interface PlayerDetector { - PlayerDetector NO_CREATIVE_PLAYERS = (level, entitySelector, pos, maxDistance, requireLineOfSight) -> entitySelector.getPlayers( -- level, player -> player.blockPosition().closerThan(pos, maxDistance) && !player.isCreative() && !player.isSpectator() -+ level, player -> player.blockPosition().closerThan(pos, maxDistance) && !player.isCreative() && !player.isSpectator() && player.affectsSpawning // Paper - Affects Spawning API + PlayerDetector NO_CREATIVE_PLAYERS = (level, selector, pos, requiredPlayerRange, requireLineOfSight) -> selector.getPlayers( +- level, p -> p.blockPosition().closerThan(pos, requiredPlayerRange) && !p.isCreative() && !p.isSpectator() ++ level, p -> p.blockPosition().closerThan(pos, requiredPlayerRange) && !p.isCreative() && !p.isSpectator() && p.affectsSpawning // Paper - Affects Spawning API ) .stream() .filter(player -> !requireLineOfSight || inLineOfSight(level, pos.getCenter(), player.getEyePosition())) diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch index 97db3c8b6051..97ff70e7bc79 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java +++ b/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java -@@ -216,7 +_,14 @@ +@@ -219,7 +_,14 @@ nextSpawnData.getEquipment().ifPresent(mob::equip); } @@ -8,7 +8,7 @@ + // Paper start - TrialSpawnerSpawnEvent + SpawnReason + entity.spawnedViaMobSpawner = true; // Mark entity as spawned via spawner + entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRIAL_SPAWNER; // Paper - Entity#getEntitySpawnReason -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callTrialSpawnerSpawnEvent(entity, pos).isCancelled()) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callTrialSpawnerSpawnEvent(entity, spawnerPos).isCancelled()) { + return Optional.empty(); + } + if (!level.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRIAL_SPAWNER)) { @@ -16,33 +16,28 @@ return Optional.empty(); } -@@ -231,10 +_,24 @@ - } - - public void ejectReward(ServerLevel level, BlockPos pos, ResourceKey lootTable) { -- LootTable lootTable1 = level.getServer().reloadableRegistries().getLootTable(lootTable); -+ LootTable lootTable1 = level.getServer().reloadableRegistries().getLootTable(lootTable); final LootTable sourceLootTable = lootTable1; // Paper - obfhelper - LootParams lootParams = new LootParams.Builder(level).create(LootContextParamSets.EMPTY); - ObjectArrayList randomItems = lootTable1.getRandomItems(lootParams); - if (!randomItems.isEmpty()) { +@@ -238,6 +_,20 @@ + LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY); + ObjectArrayList lootDrops = lootTable.getRandomItems(params); + if (!lootDrops.isEmpty()) { + // CraftBukkit start + org.bukkit.event.block.BlockDispenseLootEvent spawnerDispenseLootEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDispenseLootEvent( + level, + pos, + null, -+ randomItems, -+ sourceLootTable ++ lootDrops, ++ lootTable + ); + if (spawnerDispenseLootEvent.isCancelled()) { + return; + } + -+ randomItems = new ObjectArrayList<>(spawnerDispenseLootEvent.getDispensedLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).toList()); ++ lootDrops = new ObjectArrayList<>(spawnerDispenseLootEvent.getDispensedLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).toList()); + // CraftBukkit end - for (ItemStack itemStack : randomItems) { - DefaultDispenseItemBehavior.spawnItem(level, itemStack, 2, Direction.UP, Vec3.atBottomCenterOf(pos).relative(Direction.UP, 1.2)); + for (ItemStack item : lootDrops) { + DefaultDispenseItemBehavior.spawnItem(level, item, 2, Direction.UP, Vec3.atBottomCenterOf(pos).relative(Direction.UP, 1.2)); } -@@ -400,6 +_,35 @@ +@@ -401,6 +_,35 @@ this.requiredPlayerRange ); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java.patch index f06bd4ea7c52..2cf57ffee996 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java +++ b/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerStateData.java -@@ -186,7 +_,7 @@ +@@ -187,7 +_,7 @@ mob.dropPreservedEquipment(level); } @@ -8,4 +8,4 @@ + entity.remove(Entity.RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - Add bukkit remove cause; } }); - if (!spawner.ominousConfig().spawnPotentialsDefinition().isEmpty()) { + if (!trialSpawner.ominousConfig().spawnPotentialsDefinition().isEmpty()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch index 3af49bdb93d6..cf97617da22f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch @@ -1,88 +1,96 @@ --- a/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java +++ b/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java -@@ -256,7 +_,13 @@ - if (!list.isEmpty()) { - player.awardStat(Stats.ITEM_USED.get(stack.getItem())); - stack.consume(config.keyItem().getCount(), player); -- unlock(level, state, pos, config, serverData, sharedData, list); +@@ -280,7 +_,13 @@ + if (!itemsToEject.isEmpty()) { + player.awardStat(Stats.ITEM_USED.get(stackToInsert.getItem())); + stackToInsert.consume(config.keyItem().getCount(), player); +- unlock(serverLevel, blockState, pos, config, serverData, sharedData, itemsToEject); + // CraftBukkit start -+ LootTable sourceLootTable = level.getServer().reloadableRegistries().getLootTable(config.lootTable()); -+ org.bukkit.event.block.BlockDispenseLootEvent vaultDispenseLootEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDispenseLootEvent(level, pos, player, list, sourceLootTable); ++ LootTable sourceLootTable = serverLevel.getServer().reloadableRegistries().getLootTable(config.lootTable()); ++ org.bukkit.event.block.BlockDispenseLootEvent vaultDispenseLootEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDispenseLootEvent(serverLevel, pos, player, itemsToEject, sourceLootTable); + if (vaultDispenseLootEvent.isCancelled()) return; -+ list = vaultDispenseLootEvent.getDispensedLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).toList(); ++ itemsToEject = vaultDispenseLootEvent.getDispensedLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).toList(); + // CraftBukkit end -+ unlock(level, state, pos, config, serverData, sharedData, list, player); // Paper - Vault API ++ unlock(serverLevel, blockState, pos, config, serverData, sharedData, itemsToEject, player); // Paper - Vault API serverData.addToRewardedPlayers(player); - sharedData.updateConnectedPlayersWithinRange(level, pos, serverData, config, config.deactivationRange()); + sharedData.updateConnectedPlayersWithinRange(serverLevel, pos, serverData, config, config.deactivationRange()); } -@@ -265,8 +_,30 @@ - } - - static void setVaultState(ServerLevel level, BlockPos pos, BlockState oldState, BlockState newState, VaultConfig config, VaultSharedData sharedData) { -- VaultState vaultState = oldState.getValue(VaultBlock.STATE); -- VaultState vaultState1 = newState.getValue(VaultBlock.STATE); -+ // Paper start - Vault API -+ setVaultState(level, pos, oldState, newState, config,sharedData, null); +@@ -296,8 +_,39 @@ + final VaultConfig config, + final VaultSharedData sharedData + ) { ++ // Paper start - Vault API ++ setVaultState(serverLevel, pos, currentBlockState, newBlockState, config, sharedData, null); + } + -+ static void setVaultState(ServerLevel level, BlockPos pos, BlockState oldState, BlockState newState, VaultConfig config, VaultSharedData sharedData, @Nullable Player associatedPlayer) { -+ VaultState vaultState = oldState.getValue(VaultBlock.STATE); final VaultState oldVaultState = vaultState; -+ VaultState vaultState1 = newState.getValue(VaultBlock.STATE); final VaultState newVaultState = vaultState1; ++ static void setVaultState( ++ final ServerLevel serverLevel, ++ final BlockPos pos, ++ final BlockState currentBlockState, ++ final BlockState newBlockState, ++ final VaultConfig config, ++ final VaultSharedData sharedData, ++ final @Nullable Player associatedPlayer ++ ) { + VaultState currentVaultState = currentBlockState.getValue(VaultBlock.STATE); + VaultState newVaultState = newBlockState.getValue(VaultBlock.STATE); ++ final VaultState oldVaultState = currentVaultState; + org.bukkit.entity.Player apiAssociatedPlayer = null; + if (associatedPlayer != null) { + apiAssociatedPlayer = (org.bukkit.entity.Player) associatedPlayer.getBukkitEntity(); + } else if (newVaultState == VaultState.ACTIVE) { + final Set connectedPlayers = sharedData.getConnectedPlayers(); + if (!connectedPlayers.isEmpty()) { // Used over sharedData#hasConnectedPlayers to ensure belows iterator#next is always okay. -+ apiAssociatedPlayer = level.getCraftServer().getPlayer(connectedPlayers.iterator().next()); ++ apiAssociatedPlayer = serverLevel.getCraftServer().getPlayer(connectedPlayers.iterator().next()); + } + } + final io.papermc.paper.event.block.VaultChangeStateEvent event = new io.papermc.paper.event.block.VaultChangeStateEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), ++ org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, pos), + apiAssociatedPlayer, -+ org.bukkit.craftbukkit.block.data.CraftBlockData.toBukkit(oldVaultState, org.bukkit.block.data.type.Vault.State.class), -+ org.bukkit.craftbukkit.block.data.CraftBlockData.toBukkit(newVaultState, org.bukkit.block.data.type.Vault.State.class) ++ org.bukkit.craftbukkit.block.data.CraftBlockData.fromVanilla(oldVaultState, org.bukkit.block.data.type.Vault.State.class), ++ org.bukkit.craftbukkit.block.data.CraftBlockData.fromVanilla(newVaultState, org.bukkit.block.data.type.Vault.State.class) + ); + if (!event.callEvent()) return; -+ // Paper end - Vault API - level.setBlock(pos, newState, Block.UPDATE_ALL); - vaultState.onTransition(level, pos, vaultState1, config, sharedData, newState.getValue(VaultBlock.OMINOUS)); ++ // Paper end - Vault API + serverLevel.setBlock(pos, newBlockState, Block.UPDATE_ALL); + currentVaultState.onTransition(serverLevel, pos, newVaultState, config, sharedData, newBlockState.getValue(VaultBlock.OMINOUS)); } -@@ -278,6 +_,11 @@ - ItemStack randomDisplayItemFromLootTable = getRandomDisplayItemFromLootTable( - level, pos, config.overrideLootTableToDisplay().orElse(config.lootTable()) - ); +@@ -309,6 +_,11 @@ + sharedData.setDisplayItem(ItemStack.EMPTY); + } else { + ItemStack displayItem = getRandomDisplayItemFromLootTable(serverLevel, pos, config.overrideLootTableToDisplay().orElse(config.lootTable())); + // CraftBukkit start -+ org.bukkit.event.block.VaultDisplayItemEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVaultDisplayItemEvent(level, pos, randomDisplayItemFromLootTable); ++ org.bukkit.event.block.VaultDisplayItemEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVaultDisplayItemEvent(serverLevel, pos, displayItem); + if (event.isCancelled()) return; -+ randomDisplayItemFromLootTable = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDisplayItem()); ++ displayItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDisplayItem()); + // CraftBukkit end - sharedData.setDisplayItem(randomDisplayItemFromLootTable); + sharedData.setDisplayItem(displayItem); } } -@@ -300,10 +_,24 @@ - VaultSharedData sharedData, - List itemsToEject +@@ -331,10 +_,25 @@ + final VaultSharedData sharedData, + final List itemsToEject ) { -+ // Paper start - Vault API -+ unlock(level, state, pos, config, serverData, sharedData, itemsToEject, null); ++ // Paper start - Vault API ++ unlock(serverLevel, blockState, pos, config, serverData, sharedData, itemsToEject, null); + } ++ + private static void unlock( -+ ServerLevel level, -+ BlockState state, -+ BlockPos pos, -+ VaultConfig config, -+ VaultServerData serverData, -+ VaultSharedData sharedData, -+ List itemsToEject, ++ final ServerLevel serverLevel, ++ final BlockState blockState, ++ final BlockPos pos, ++ final VaultConfig config, ++ final VaultServerData serverData, ++ final VaultSharedData sharedData, ++ final List itemsToEject, + final @Nullable Player associatedPlayer + ) { -+ // Paper end - Vault API ++ // Paper end - Vault API serverData.setItemsToEject(itemsToEject); sharedData.setDisplayItem(serverData.getNextItemToEject()); - serverData.pauseStateUpdatingUntil(level.getGameTime() + 14L); -- setVaultState(level, pos, state, state.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData); -+ setVaultState(level, pos, state, state.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData, associatedPlayer); // Paper - Vault API + serverData.pauseStateUpdatingUntil(serverLevel.getGameTime() + 14L); +- setVaultState(serverLevel, pos, blockState, blockState.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData); ++ setVaultState(serverLevel, pos, blockState, blockState.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData, associatedPlayer); // Paper - Vault API } - private static List resolveItemsToEject(ServerLevel level, VaultConfig config, BlockPos pos, Player player, ItemStack key) { + private static List resolveItemsToEject( diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch index 3b7f68bd0e66..923e9d99c960 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch @@ -3,7 +3,7 @@ @@ -62,7 +_,12 @@ @VisibleForTesting - public void addToRewardedPlayers(Player player) { + public void addToRewardedPlayers(final Player player) { - this.rewardedPlayers.add(player.getUUID()); + // Paper start - Vault API + addToRewardedPlayers(player.getUUID()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch index 40be0c223f58..19d3e28e7056 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch @@ -1,24 +1,24 @@ --- a/net/minecraft/world/level/block/grower/TreeGrower.java +++ b/net/minecraft/world/level/block/grower/TreeGrower.java -@@ -130,6 +_,7 @@ - .get(configuredMegaFeature) +@@ -132,6 +_,7 @@ + .get(megaFeatureKey) .orElse(null); - if (holder != null) { -+ this.setTreeType(holder); // CraftBukkit - for (int i = 0; i >= -1; i--) { - for (int i1 = 0; i1 >= -1; i1--) { - if (isTwoByTwoSapling(state, level, pos, i, i1)) { -@@ -162,6 +_,7 @@ - if (holder1 == null) { + if (featureHolder != null) { ++ this.setTreeType(featureHolder); // CraftBukkit + for (int dx = 0; dx >= -1; dx--) { + for (int dz = 0; dz >= -1; dz--) { + if (isTwoByTwoSapling(state, level, pos, dx, dz)) { +@@ -164,6 +_,7 @@ + if (featureHolder == null) { return false; } else { -+ this.setTreeType(holder1); // CraftBukkit - ConfiguredFeature configuredFeature2 = holder1.value(); - BlockState blockState1 = level.getFluidState(pos).createLegacyBlock(); - level.setBlock(pos, blockState1, Block.UPDATE_NONE); -@@ -196,4 +_,58 @@ - - return false; ++ this.setTreeType(featureHolder); // CraftBukkit + ConfiguredFeature feature = featureHolder.value(); + BlockState emptyBlock = level.getFluidState(pos).createLegacyBlock(); + level.setBlock(pos, emptyBlock, Block.UPDATE_NONE); +@@ -210,4 +_,58 @@ + : OptionalInt.empty(); + } } + + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch index 656349adc962..e0e76a8fab22 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java +++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java -@@ -152,6 +_,12 @@ +@@ -150,6 +_,12 @@ @Override - protected boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) { + protected boolean triggerEvent(final BlockState state, final Level level, final BlockPos pos, final int b0, final int b1) { Direction direction = state.getValue(FACING); + // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur) -+ Direction directionQueuedAs = Direction.from3DDataValue(param & 7); // Paper - copied from below ++ Direction directionQueuedAs = Direction.from3DDataValue(b1 & 7); // Paper - copied from below + if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) { + return false; + } + // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - BlockState blockState = state.setValue(EXTENDED, true); + BlockState extendedState = state.setValue(EXTENDED, true); if (!level.isClientSide()) { - boolean neighborSignal = this.getNeighborSignal(level, pos, direction); -@@ -183,10 +_,17 @@ + boolean extend = this.getNeighborSignal(level, pos, direction); +@@ -182,10 +_,17 @@ .defaultBlockState() .setValue(MovingPistonBlock.FACING, direction) .setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT); @@ -24,20 +24,20 @@ + } + } + // Paper end - Fix sticky pistons and BlockPistonRetractEvent - level.setBlock(pos, blockState1, Block.UPDATE_NONE | Block.UPDATE_KNOWN_SHAPE); + level.setBlock(pos, movingPistonState, Block.UPDATE_NONE | Block.UPDATE_KNOWN_SHAPE); level.setBlockEntity( MovingPistonBlock.newMovingBlockEntity( -- pos, blockState1, this.defaultBlockState().setValue(FACING, Direction.from3DDataValue(param & 7)), direction, false, true -+ pos, blockState1, this.defaultBlockState().setValue(FACING, Direction.from3DDataValue(param & 7)), direction, false, true // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change +- pos, movingPistonState, this.defaultBlockState().setValue(FACING, Direction.from3DDataValue(b1 & 7)), direction, false, true ++ pos, movingPistonState, this.defaultBlockState().setValue(FACING, Direction.from3DDataValue(b1 & 7)), direction, false, true // Paper - Protect Bedrock and End Portal/Frames from being destroyed; diff on change ) ); - level.updateNeighborsAt(pos, blockState1.getBlock()); -@@ -210,13 +_,27 @@ - || blockState2.getPistonPushReaction() != PushReaction.NORMAL - && !blockState2.is(Blocks.PISTON) - && !blockState2.is(Blocks.STICKY_PISTON)) { + level.updateNeighborsAt(pos, movingPistonState.getBlock()); +@@ -209,13 +_,27 @@ + || movingState.getPistonPushReaction() != PushReaction.NORMAL + && !movingState.is(Blocks.PISTON) + && !movingState.is(Blocks.STICKY_PISTON)) { + // Paper start - Fix sticky pistons and BlockPistonRetractEvent; fire BlockPistonRetractEvent for sticky pistons retracting nothing (air) -+ if (id == TRIGGER_CONTRACT && blockState1.isAir()) { ++ if (b0 == TRIGGER_CONTRACT && movingState.isAir()) { + if (!new org.bukkit.event.block.BlockPistonRetractEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), java.util.Collections.emptyList(), org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction)).callEvent()) { + return false; + } @@ -60,25 +60,25 @@ + // Paper end - Protect Bedrock and End Portal/Frames from being destroyed } - level.playSound(null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, level.random.nextFloat() * 0.15F + 0.6F); -@@ -227,7 +_,7 @@ - } - - public static boolean isPushable(BlockState state, Level level, BlockPos pos, Direction movementDirection, boolean allowDestroy, Direction pistonFacing) { + level.playSound(null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, random.nextFloat() * 0.15F + 0.6F); +@@ -233,7 +_,7 @@ + final boolean allowDestroyable, + final Direction connectionDirection + ) { - if (pos.getY() < level.getMinY() || pos.getY() > level.getMaxY() || !level.getWorldBorder().isWithinBounds(pos)) { -+ if (pos.getY() < level.getMinY() || pos.getY() > level.getMaxY() || !level.getWorldBorder().isWithinBounds(pos) || !level.getWorldBorder().isWithinBounds(pos.relative(movementDirection))) { // Paper - Fix piston world border check ++ if (pos.getY() < level.getMinY() || pos.getY() > level.getMaxY() || !level.getWorldBorder().isWithinBounds(pos) || !level.getWorldBorder().isWithinBounds(pos.relative(direction))) { // Paper - Fix piston world border check return false; } else if (state.isAir()) { return true; -@@ -283,12 +_,54 @@ - BlockState[] blockStates = new BlockState[toPush.size() + toDestroy.size()]; - Direction direction = extending ? facing : facing.getOpposite(); - int i = 0; +@@ -289,12 +_,58 @@ + BlockState[] toUpdate = new BlockState[toPush.size() + toDestroy.size()]; + Direction pushDirection = extending ? direction : direction.getOpposite(); + int updateIndex = 0; + // CraftBukkit start -+ final org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ final org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pistonPos); + -+ final List moved = pistonStructureResolver.getToPush(); -+ final List broken = pistonStructureResolver.getToDestroy(); ++ final List moved = resolver.getToPush(); ++ final List broken = resolver.getToDestroy(); + + List blocks = new java.util.AbstractList<>() { + @@ -100,9 +100,13 @@ + + final org.bukkit.event.block.BlockPistonEvent event; + if (extending) { -+ event = new org.bukkit.event.block.BlockPistonExtendEvent(bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction)); ++ event = new org.bukkit.event.block.BlockPistonExtendEvent( ++ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) ++ ); + } else { -+ event = new org.bukkit.event.block.BlockPistonRetractEvent(bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction)); ++ event = new org.bukkit.event.block.BlockPistonRetractEvent( ++ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) ++ ); + } + if (!event.callEvent()) { + for (BlockPos brokenPos : broken) { @@ -110,49 +114,51 @@ + } + for (BlockPos movedPos : moved) { + level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); -+ movedPos = movedPos.relative(direction); ++ movedPos = movedPos.relative(pushDirection); + level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); + } + return false; + } + // CraftBukkit end - for (int i1 = toDestroy.size() - 1; i1 >= 0; i1--) { - BlockPos blockPos2 = toDestroy.get(i1); - BlockState blockState1 = level.getBlockState(blockPos2); - BlockEntity blockEntity = blockState1.hasBlockEntity() ? level.getBlockEntity(blockPos2) : null; -- dropResources(blockState1, level, blockPos2, blockEntity); -+ dropResources(blockState1, level, blockPos2, blockEntity, pos); // Paper - Add BlockBreakBlockEvent - if (!blockState1.is(BlockTags.FIRE) && level.isClientSide()) { - level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos2, getId(blockState1)); + for (int i = toDestroy.size() - 1; i >= 0; i--) { + BlockPos pos = toDestroy.get(i); + BlockState state = level.getBlockState(pos); + BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; +- dropResources(state, level, pos, blockEntity); ++ dropResources(state, level, pos, blockEntity, pistonPos); // Paper - Add BlockBreakBlockEvent + if (!state.is(BlockTags.FIRE) && level.isClientSide()) { + level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, getId(state)); } -@@ -299,13 +_,26 @@ +@@ -305,13 +_,28 @@ } - for (int i1 = toPush.size() - 1; i1 >= 0; i1--) { -- BlockPos blockPos2 = toPush.get(i1); -- BlockState blockState1 = level.getBlockState(blockPos2); + for (int i = toPush.size() - 1; i >= 0; i--) { +- BlockPos pos = toPush.get(i); +- BlockState blockState = level.getBlockState(pos); + // Paper start - fix a variety of piston desync dupes + boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; -+ BlockPos blockPos2; -+ BlockPos oldPos = blockPos2 = toPush.get(i1); -+ BlockState blockState1 = allowDesync ? level.getBlockState(oldPos) : null; ++ BlockPos oldPos = toPush.get(i); ++ BlockPos pos = oldPos; ++ BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null; + // Paper end - fix a variety of piston desync dupes - blockPos2 = blockPos2.relative(direction); - map.remove(blockPos2); - BlockState blockState2 = Blocks.MOVING_PISTON.defaultBlockState().setValue(FACING, facing); - level.setBlock(blockPos2, blockState2, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON); -- level.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockPos2, blockState2, list.get(i1), facing, extending, false)); + pos = pos.relative(pushDirection); + deleteAfterMove.remove(pos); + BlockState actualState = Blocks.MOVING_PISTON.defaultBlockState().setValue(FACING, direction); + level.setBlock(pos, actualState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON); +- level.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, actualState, toPushShapes.get(i), direction, extending, false)); + // Paper start - fix a variety of piston desync dupes + if (!allowDesync) { -+ blockState1 = level.getBlockState(oldPos); -+ map.replace(oldPos, blockState1); ++ blockState = level.getBlockState(oldPos); ++ deleteAfterMove.replace(oldPos, blockState); + } -+ level.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockPos2, blockState2, allowDesync ? list.get(i1) : blockState1, facing, extending, false)); ++ level.setBlockEntity( ++ MovingPistonBlock.newMovingBlockEntity(pos, actualState, allowDesync ? toPushShapes.get(i) : blockState, direction, extending, false) ++ ); + if (!allowDesync) { + level.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_SKIP_ON_PLACE); // set air to prevent later physics updates from seeing this block + } + // Paper end - fix a variety of piston desync dupes - blockStates[i++] = blockState1; + toUpdate[updateIndex++] = blockState; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch index aaec6b4a7586..7886dd0655bd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch @@ -9,12 +9,12 @@ private boolean extending = false; private boolean isSourcePiston = false; private static final ThreadLocal NOCLIP = ThreadLocal.withInitial(() -> null); -@@ -309,7 +_,7 @@ +@@ -319,7 +_,7 @@ if (level.getBlockState(pos).is(Blocks.MOVING_PISTON)) { - BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, level, pos); - if (blockState.isAir()) { -- level.setBlock(pos, blockEntity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE); -+ level.setBlock(pos, blockEntity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air - Block.updateOrDestroy(blockEntity.movedState, blockState, level, pos, Block.UPDATE_ALL); + BlockState newState = Block.updateFromNeighbourShapes(entity.movedState, level, pos); + if (newState.isAir()) { +- level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE); ++ level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air + Block.updateOrDestroy(entity.movedState, newState, level, pos, Block.UPDATE_ALL); } else { - if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) { + if (newState.hasProperty(BlockStateProperties.WATERLOGGED) && newState.getValue(BlockStateProperties.WATERLOGGED)) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch index bde64a653281..c8f8a45f71e8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -167,13 +_,20 @@ +@@ -169,15 +_,22 @@ } - protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { + org.spigotmc.AsyncCatcher.catchOp("block onPlace"); // Spigot } - protected void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) { + protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) { } + // CraftBukkit start @@ -16,51 +16,53 @@ + } + // CraftBukkit end + - protected void onExplosionHit(BlockState state, ServerLevel level, BlockPos pos, Explosion explosion, BiConsumer dropConsumer) { + protected void onExplosionHit( + final BlockState state, final ServerLevel level, final BlockPos pos, final Explosion explosion, final BiConsumer onHit + ) { - if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) { + if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed Block block = state.getBlock(); - boolean flag = explosion.getIndirectSourceEntity() instanceof Player; + boolean doDropExperienceHack = explosion.getIndirectSourceEntity() instanceof Player; if (block.dropFromExplosion(explosion)) { -@@ -183,8 +_,10 @@ +@@ -187,8 +_,10 @@ .withParameter(LootContextParams.TOOL, ItemStack.EMPTY) .withOptionalParameter(LootContextParams.BLOCK_ENTITY, blockEntity) .withOptionalParameter(LootContextParams.THIS_ENTITY, explosion.getDirectSourceEntity()); - if (explosion.getBlockInteraction() == Explosion.BlockInteraction.DESTROY_WITH_DECAY) { -- builder.withParameter(LootContextParams.EXPLOSION_RADIUS, explosion.radius()); +- params.withParameter(LootContextParams.EXPLOSION_RADIUS, explosion.radius()); + // CraftBukkit start - add yield + if (explosion instanceof net.minecraft.world.level.ServerExplosion serverExplosion && serverExplosion.yield < 1.0F) { -+ builder.withParameter(LootContextParams.EXPLOSION_RADIUS, 1.0F / serverExplosion.yield); ++ params.withParameter(LootContextParams.EXPLOSION_RADIUS, 1.0F / serverExplosion.yield); + // CraftBukkit end } - state.spawnAfterBreak(level, pos, ItemStack.EMPTY, flag); -@@ -256,7 +_,7 @@ + state.spawnAfterBreak(level, pos, ItemStack.EMPTY, doDropExperienceHack); +@@ -268,7 +_,7 @@ } - protected boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) { -- return state.canBeReplaced() && (useContext.getItemInHand().isEmpty() || !useContext.getItemInHand().is(this.asItem())); -+ return state.canBeReplaced() && (useContext.getItemInHand().isEmpty() || !useContext.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (useContext.getPlayer() != null && useContext.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed + protected boolean canBeReplaced(final BlockState state, final BlockPlaceContext context) { +- return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())); ++ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed } - protected boolean canBeReplaced(BlockState state, Fluid fluid) { -@@ -466,6 +_,15 @@ + protected boolean canBeReplaced(final BlockState state, final Fluid fluid) { +@@ -483,6 +_,15 @@ this.instrument = properties.instrument; this.replaceable = properties.replaceable; } + // Paper start - Perf: impl cached craft block data, lazy load to fix issue with loading at the wrong time -+ private org.bukkit.craftbukkit.block.data.@Nullable CraftBlockData cachedCraftBlockData; ++ private org.bukkit.craftbukkit.block.data.@Nullable CraftBlockData cachedBlockData; + -+ public org.bukkit.craftbukkit.block.data.CraftBlockData createCraftBlockData() { -+ if (this.cachedCraftBlockData == null) this.cachedCraftBlockData = org.bukkit.craftbukkit.block.data.CraftBlockData.createData(this.asState()); -+ return (org.bukkit.craftbukkit.block.data.CraftBlockData) this.cachedCraftBlockData.clone(); ++ public org.bukkit.craftbukkit.block.data.CraftBlockData asBlockData() { ++ if (this.cachedBlockData == null) this.cachedBlockData = org.bukkit.craftbukkit.block.data.CraftBlockData.createData(this.asState()); ++ return (org.bukkit.craftbukkit.block.data.CraftBlockData) this.cachedBlockData.clone(); + } + // Paper end - Perf: impl cached craft block data, lazy load to fix issue with loading at the wrong time + private boolean calculateSolid() { if (this.owner.properties.forceSolidOn) { -@@ -485,12 +_,14 @@ +@@ -502,12 +_,14 @@ } } @@ -75,7 +77,7 @@ this.legacySolid = this.calculateSolid(); this.occlusionShape = this.canOcclude ? this.owner.getOcclusionShape(this.asState()) : Shapes.empty(); -@@ -529,6 +_,11 @@ +@@ -547,6 +_,11 @@ public boolean isSolid() { return this.legacySolid; } @@ -85,9 +87,9 @@ + } + // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - public boolean isValidSpawn(BlockGetter level, BlockPos pos, EntityType entityType) { - return this.getBlock().properties.isValidSpawn.test(this.asState(), level, pos, entityType); -@@ -550,19 +_,19 @@ + public boolean isValidSpawn(final BlockGetter level, final BlockPos pos, final EntityType type) { + return this.getBlock().properties.isValidSpawn.test(this.asState(), level, pos, type); +@@ -568,19 +_,19 @@ return this.occlusionShape; } @@ -112,7 +114,16 @@ return this.isAir; } -@@ -632,14 +_,14 @@ +@@ -594,7 +_,7 @@ + } + + public MapColor getMapColor(final BlockGetter level, final BlockPos pos) { +- return this.mapColor; ++ return this.mapColor; // Paper - diff on change - ensure level and pos are never used for CraftBlockData#getMapColor + } + + public BlockState rotate(final Rotation rotation) { +@@ -650,14 +_,14 @@ } public PushReaction getPistonPushReaction() { @@ -129,10 +140,10 @@ return this.canOcclude; } -@@ -726,7 +_,13 @@ +@@ -748,7 +_,13 @@ } - public void onPlace(Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + public void onPlace(final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { - this.getBlock().onPlace(this.asState(), level, pos, oldState, movedByPiston); + // CraftBukkit start + this.onPlace(level, pos, oldState, movedByPiston, null); @@ -143,17 +154,17 @@ + // CraftBukkit end } - public void affectNeighborsAfterRemoval(ServerLevel level, BlockPos pos, boolean movedByPiston) { -@@ -751,6 +_,7 @@ + public void affectNeighborsAfterRemoval(final ServerLevel level, final BlockPos pos, final boolean movedByPiston) { +@@ -775,6 +_,7 @@ - public void spawnAfterBreak(ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { - this.getBlock().spawnAfterBreak(this.asState(), level, pos, stack, dropExperience); -+ if (dropExperience) {this.getBlock().popExperience(level, pos, this.getBlock().getExpDrop(this.asState(), level, pos, stack, true));} // Paper - Properly handle xp dropping + public void spawnAfterBreak(final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { + this.getBlock().spawnAfterBreak(this.asState(), level, pos, tool, dropExperience); ++ if (dropExperience) {this.getBlock().popExperience(level, pos, this.getBlock().getExpDrop(this.asState(), level, pos, tool, true));} // Paper - Properly handle xp dropping } - public List getDrops(LootParams.Builder lootParams) { -@@ -857,11 +_,11 @@ - return this.getBlock().builtInRegistryHolder().is(block); + public List getDrops(final LootParams.Builder params) { +@@ -859,11 +_,11 @@ + return this.getBlock() instanceof EntityBlock ? ((EntityBlock)this.getBlock()).getTicker(level, this.asState(), type) : null; } - public FluidState getFluidState() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockState.java.patch index d13dde221670..7164d1227d06 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockState.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/block/state/BlockState.java +++ b/net/minecraft/world/level/block/state/BlockState.java -@@ -10,6 +_,17 @@ +@@ -8,6 +_,17 @@ public class BlockState extends BlockBehaviour.BlockStateBase { - public static final Codec CODEC = codec(BuiltInRegistries.BLOCK.byNameCodec(), Block::defaultBlockState).stable(); + public static final Codec CODEC = codec(BuiltInRegistries.BLOCK.byNameCodec(), Block::defaultBlockState, Block::getStateDefinition).stable(); + // Paper start - optimise getType calls -+ @javax.annotation.Nullable org.bukkit.Material cachedMaterial; ++ org.bukkit.@org.jspecify.annotations.Nullable Material cachedMaterial; + + public final org.bukkit.Material getBukkitMaterial() { + if (this.cachedMaterial == null) { @@ -15,6 +15,6 @@ + } + // Paper end - optimise getType calls + - public BlockState(Block owner, Reference2ObjectArrayMap, Comparable> values, MapCodec propertiesCodec) { - super(owner, values, propertiesCodec); + public BlockState(final Block owner, final Property[] propertyKeys, final Comparable[] propertyValues) { + super(owner, propertyKeys, propertyValues); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch new file mode 100644 index 000000000000..7770ed3eef7b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/state/StateHolder.java ++++ b/net/minecraft/world/level/block/state/StateHolder.java +@@ -142,7 +_,7 @@ + return length == 0 ? Stream.empty() : IntStream.range(0, length).mapToObj(i -> createValue(this.propertyKeys[i], this.propertyValues[i])); + } + +- private static > Property.Value createValue(final Property propertyKey, final Comparable propertyValue) { ++ public static > Property.Value createValue(final Property propertyKey, final Comparable propertyValue) { // Paper - public + return new Property.Value<>(propertyKey, (T)propertyValue); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/EnumProperty.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/EnumProperty.java.patch index 94537a6a1d4b..d4296e9e0b13 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/EnumProperty.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/EnumProperty.java.patch @@ -5,8 +5,8 @@ } - @Override -- public boolean equals(Object other) { -+ public boolean equals_unused(Object other) { // Paper - Perf: Optimize hashCode/equals - return this == other || other instanceof EnumProperty enumProperty && super.equals(other) && this.values.equals(enumProperty.values); +- public boolean equals(final Object o) { ++ public boolean equals_unused(final Object o) { // Paper - Perf: Optimize hashCode/equals + return this == o || o instanceof EnumProperty that && super.equals(o) && this.values.equals(that.values); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch index a3b33fce2067..93d336613a43 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch @@ -5,8 +5,8 @@ } - @Override -- public boolean equals(Object other) { -+ public boolean equals_unused(Object other) { // Paper - Perf: Optimize hashCode/equals - return this == other || other instanceof IntegerProperty integerProperty && super.equals(other) && this.values.equals(integerProperty.values); +- public boolean equals(final Object o) { ++ public boolean equals_unused(final Object o) { // Paper - Perf: Optimize hashCode/equals + return this == o || o instanceof IntegerProperty that && super.equals(o) && this.values.equals(that.values); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/Property.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/Property.java.patch index 9087bd5e8570..0afc95954a3b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/Property.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/Property.java.patch @@ -3,9 +3,9 @@ @@ -71,7 +_,7 @@ @Override - public boolean equals(Object other) { -- return this == other || other instanceof Property property && this.clazz.equals(property.clazz) && this.name.equals(property.name); -+ return this == other; // Paper - Perf: Optimize hashCode/equals + public boolean equals(final Object o) { +- return this == o || o instanceof Property that && this.clazz.equals(that.clazz) && this.name.equals(that.name); ++ return this == o; // Paper - Perf: Optimize hashCode/equals } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch b/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch index 33463ef911fb..7b0b08da15d3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/border/WorldBorder.java +++ b/net/minecraft/world/level/border/WorldBorder.java -@@ -33,6 +_,8 @@ - double centerZ; - int absoluteMaxSize = 29999984; - WorldBorder.BorderExtent extent = new WorldBorder.StaticBorderExtent(5.999997E7F); +@@ -37,6 +_,8 @@ + private double centerZ; + private int absoluteMaxSize = 29999984; + private WorldBorder.BorderExtent extent = new WorldBorder.StaticBorderExtent(5.999997E7F); + public net.minecraft.server.level.@org.jspecify.annotations.Nullable ServerLevel world; // CraftBukkit + private int lastTick = -1; // Paper - Prevent ticking virtual world borders multiple times per server tick public WorldBorder() { this(WorldBorder.Settings.DEFAULT); -@@ -54,6 +_,20 @@ - return this.isWithinBounds(chunkPos.getMinBlockX(), chunkPos.getMinBlockZ()) && this.isWithinBounds(chunkPos.getMaxBlockX(), chunkPos.getMaxBlockZ()); +@@ -58,6 +_,20 @@ + return this.isWithinBounds(pos.getMinBlockX(), pos.getMinBlockZ()) && this.isWithinBounds(pos.getMaxBlockX(), pos.getMaxBlockZ()); } + // Paper start - Bound treasure maps to world border @@ -27,16 +27,18 @@ + } + // Paper end - Bound treasure maps to world border + - public boolean isWithinBounds(AABB box) { - return this.isWithinBounds(box.minX, box.minZ, box.maxX - 1.0E-5F, box.maxZ - 1.0E-5F); + public boolean isWithinBounds(final AABB aabb) { + return this.isWithinBounds(aabb.minX, aabb.minZ, aabb.maxX - 1.0E-5F, aabb.maxZ - 1.0E-5F); } -@@ -158,6 +_,14 @@ +@@ -161,7 +_,15 @@ + return this.centerZ; } - public void setCenter(double x, double z) { -+ // Paper start - Add worldborder events +- public void setCenter(final double x, final double z) { ++ // Paper start - Add worldborder events ++ public void setCenter(double x, double z) { + if (this.world != null) { -+ io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), new org.bukkit.Location(world.getWorld(), this.getCenterX(), 0, this.getCenterZ()), new org.bukkit.Location(world.getWorld(), x, 0, z)); ++ io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderCenterChangeEvent(this.world.getWorld(), this.world.getWorld().getWorldBorder(), new org.bukkit.Location(this.world.getWorld(), this.getCenterX(), 0, this.getCenterZ()), new org.bukkit.Location(this.world.getWorld(), this.centerX, 0, this.centerZ)); + if (!event.callEvent()) return; + x = event.getNewCenter().getX(); + z = event.getNewCenter().getZ(); @@ -45,13 +47,15 @@ this.centerX = x; this.centerZ = z; this.extent.onCenterChange(); -@@ -181,6 +_,17 @@ +@@ -184,7 +_,18 @@ + return this.extent.getLerpTarget(); } - public void setSize(double size) { -+ // Paper start - Add worldborder events +- public void setSize(final double size) { ++ // Paper start - Add worldborder events ++ public void setSize(double size) { + if (this.world != null) { -+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE, getSize(), size, 0); ++ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(this.world.getWorld(), this.world.getWorld().getWorldBorder(), io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE, getSize(), size, 0); + if (!event.callEvent()) return; + if (event.getType() == io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE && event.getDurationTicks() > 0) { // If changed to a timed transition + lerpSizeBetween(event.getOldSize(), event.getNewSize(), event.getDurationTicks(), this.world.getGameTime()); @@ -63,36 +67,38 @@ this.extent = new WorldBorder.StaticBorderExtent(size); this.setDirty(); -@@ -190,6 +_,20 @@ +@@ -193,7 +_,21 @@ + } } - public void lerpSizeBetween(double oldSize, double newSize, long time, long startTime) { -+ // Paper start - Add worldborder events +- public void lerpSizeBetween(final double from, final double to, final long ticks, final long gameTime) { ++ // Paper start - Add worldborder events ++ public void lerpSizeBetween(final double from, double to, long ticks, final long gameTime) { + if (this.world != null) { + io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type type; -+ if (oldSize == newSize) { // new size = old size ++ if (from == to) { // new size = old size + type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.INSTANT_MOVE; // Use INSTANT_MOVE because below it creates a Static border if they are equal. + } else { + type = io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent.Type.STARTED_MOVE; + } -+ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(world.getWorld(), world.getWorld().getWorldBorder(), type, oldSize, newSize, time); ++ io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent event = new io.papermc.paper.event.world.border.WorldBorderBoundsChangeEvent(this.world.getWorld(), this.world.getWorld().getWorldBorder(), type, from, to, ticks); + if (!event.callEvent()) return; -+ newSize = event.getNewSize(); -+ time = event.getDurationTicks(); ++ to = event.getNewSize(); ++ ticks = event.getDurationTicks(); + } + // Paper end - Add worldborder events - this.extent = (WorldBorder.BorderExtent)(oldSize == newSize - ? new WorldBorder.StaticBorderExtent(newSize) - : new WorldBorder.MovingBorderExtent(oldSize, newSize, time, startTime)); -@@ -205,6 +_,7 @@ + this.extent = (WorldBorder.BorderExtent)(from == to + ? new WorldBorder.StaticBorderExtent(to) + : new WorldBorder.MovingBorderExtent(from, to, ticks, gameTime)); +@@ -209,6 +_,7 @@ } - public void addListener(BorderChangeListener listener) { + public void addListener(final BorderChangeListener listener) { + if (this.listeners.contains(listener)) return; // CraftBukkit this.listeners.add(listener); } -@@ -278,6 +_,12 @@ +@@ -282,6 +_,12 @@ } public void tick() { @@ -105,7 +111,7 @@ this.extent = this.extent.update(); } -@@ -298,6 +_,22 @@ +@@ -302,6 +_,22 @@ } } @@ -125,10 +131,10 @@ + } + // Paper end - add back applySettings + - interface BorderExtent { - double getMinX(float partialTick); + private interface BorderExtent { + double getMinX(final float deltaPartialTick); -@@ -432,6 +_,7 @@ +@@ -438,6 +_,7 @@ this.previousSize = this.size; this.size = this.calculateSize(); if (this.lerpProgress <= 0L) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch index 05cc529bf4e7..12e7f570ed5c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch @@ -19,14 +19,14 @@ + // CraftBukkit end public ChunkAccess( - ChunkPos chunkPos, + final ChunkPos chunkPos, @@ -89,7 +_,8 @@ - LevelChunkSection @Nullable [] sections, - @Nullable BlendingData blendingData + final LevelChunkSection @Nullable [] sections, + final @Nullable BlendingData blendingData ) { - this.chunkPos = chunkPos; -+ this.locX = chunkPos.x; this.locZ = chunkPos.z; // Paper - reduce need for field lookups -+ this.chunkPos = chunkPos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key ++ this.locX = chunkPos.x(); this.locZ = chunkPos.z(); // Paper - reduce need for field lookups ++ this.chunkPos = chunkPos; this.coordinateKey = ChunkPos.pack(this.locX, this.locZ); // Paper - cache long key this.upgradeData = upgradeData; this.levelHeightAccessor = levelHeightAccessor; this.sections = new LevelChunkSection[levelHeightAccessor.getSectionsCount()]; @@ -36,7 +36,7 @@ + public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper + - public @Nullable BlockState setBlockState(BlockPos pos, BlockState state) { + public @Nullable BlockState setBlockState(final BlockPos pos, final BlockState state) { return this.setBlockState(pos, state, Block.UPDATE_ALL); } @@ -266,6 +_,7 @@ @@ -57,7 +57,7 @@ public abstract ChunkStatus getPersistedStatus(); @@ -438,6 +_,22 @@ - throw new ReportedException(crashReport); + throw new ReportedException(report); } } + // CraftBukkit start @@ -77,5 +77,5 @@ + } + // CraftBukkit end - public void fillBiomesFromNoise(BiomeResolver resolver, Climate.Sampler sampler) { + public void fillBiomesFromNoise(final BiomeResolver biomeResolver, final Climate.Sampler sampler) { ChunkPos pos = this.getPos(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch index 376a148b6da3..f720ddd15a5a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch @@ -1,26 +1,32 @@ --- a/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -104,8 +_,8 @@ +@@ -105,8 +_,8 @@ protected abstract MapCodec codec(); -- public ChunkGeneratorStructureState createState(HolderLookup structureSetLookup, RandomState randomState, long seed) { -- return ChunkGeneratorStructureState.createForNormal(randomState, seed, this.biomeSource, structureSetLookup); -+ public ChunkGeneratorStructureState createState(HolderLookup structureSetLookup, RandomState randomState, long seed, org.spigotmc.SpigotWorldConfig conf) { // Spigot -+ return ChunkGeneratorStructureState.createForNormal(randomState, seed, this.biomeSource, structureSetLookup, conf); // Spigot +- public ChunkGeneratorStructureState createState(final HolderLookup structureSets, final RandomState randomState, final long legacyLevelSeed) { +- return ChunkGeneratorStructureState.createForNormal(randomState, legacyLevelSeed, this.biomeSource, structureSets); ++ public ChunkGeneratorStructureState createState(final HolderLookup structureSets, final RandomState randomState, final long legacyLevelSeed, final org.spigotmc.SpigotWorldConfig conf) { // Spigot ++ return ChunkGeneratorStructureState.createForNormal(randomState, legacyLevelSeed, this.biomeSource, structureSets, conf); // Spigot } - public Optional>> getTypeNameForDataFixer() { -@@ -129,6 +_,24 @@ + public Optional getTypeNameForDataFixer() { +@@ -127,11 +_,29 @@ + ); + + public @Nullable Pair> findNearestMapStructure( +- final ServerLevel level, final HolderSet wantedStructures, final BlockPos pos, final int maxSearchRadius, final boolean createReference ++ final ServerLevel level, HolderSet wantedStructures, BlockPos pos, int maxSearchRadius, boolean createReference + ) { if (SharedConstants.DEBUG_DISABLE_FEATURES) { return null; } else { + // Paper start - StructuresLocateEvent + final org.bukkit.World bukkitWorld = level.getWorld(); + final org.bukkit.Location origin = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level); -+ final List apiStructures = structure.stream().map(org.bukkit.craftbukkit.generator.structure.CraftStructure::minecraftHolderToBukkit).toList(); ++ final List apiStructures = wantedStructures.stream().map(org.bukkit.craftbukkit.generator.structure.CraftStructure::minecraftHolderToBukkit).toList(); + if (!apiStructures.isEmpty()) { -+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipKnownStructures); ++ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, maxSearchRadius, createReference); + if (!event.callEvent()) { + return null; + } @@ -28,77 +34,75 @@ + return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraftHolder(event.getResult().structure())); + } + pos = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(event.getOrigin()); -+ radius = event.getRadius(); -+ skipKnownStructures = event.shouldFindUnexplored(); -+ structure = HolderSet.direct(org.bukkit.craftbukkit.generator.structure.CraftStructure::bukkitToMinecraftHolder, event.getStructures()); ++ maxSearchRadius = event.getRadius(); ++ createReference = event.shouldFindUnexplored(); ++ wantedStructures = HolderSet.direct(org.bukkit.craftbukkit.generator.structure.CraftStructure::bukkitToMinecraftHolder, event.getStructures()); + } + // Paper end ChunkGeneratorStructureState generatorState = level.getChunkSource().getGeneratorState(); - Map>> map = new Object2ObjectArrayMap<>(); + Map>> placementScans = new Object2ObjectArrayMap<>(); -@@ -223,6 +_,7 @@ - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); +@@ -226,6 +_,7 @@ + BlockPos.MutableBlockPos structurePos = new BlockPos.MutableBlockPos(); - for (ChunkPos chunkPos : ringPositionsFor) { -+ if (!level.paperConfig().environment.locateStructuresOutsideWorldBorder && !level.getWorldBorder().isChunkInBounds(chunkPos.x, chunkPos.z)) { continue; } // Paper - Bound treasure maps to world border - mutableBlockPos.set(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z, 8)); - double d1 = mutableBlockPos.distSqr(pos); - boolean flag = pair == null || d1 < d; -@@ -255,11 +_,15 @@ - int spacing = spreadPlacement.spacing(); + for (ChunkPos chunkPos : positions) { ++ if (!level.paperConfig().environment.locateStructuresOutsideWorldBorder && !level.getWorldBorder().isChunkInBounds(chunkPos.x(), chunkPos.z())) { continue; } // Paper - Bound treasure maps to world border + structurePos.set(SectionPos.sectionToBlockCoord(chunkPos.x(), 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z(), 8)); + double distSqr = structurePos.distSqr(pos); + boolean isClosest = closestPos == null || distSqr < closest; +@@ -260,9 +_,12 @@ + for (int x = -radius; x <= radius; x++) { + boolean xEdge = x == -radius || x == radius; - for (int i = -z; i <= z; i++) { -- boolean flag = i == -z || i == z; +- for (int z = -radius; z <= radius; z++) { +- boolean zEdge = z == -radius || z == radius; +- if (xEdge || zEdge) { + // Paper start - Perf: iterate over border chunks instead of entire square chunk area -+ final int radius = z; -+ boolean flag = i == -z || i == z; final boolean onBorderAlongZAxis = flag; // Paper - OBFHELPER - -- for (int i1 = -z; i1 <= z; i1++) { -- boolean flag1 = i1 == -z || i1 == z; -- if (flag || flag1) { -+ for (int i1 = -radius; i1 <= radius; i1 += onBorderAlongZAxis ? 1 : radius * 2) { -+ // boolean flag1 = i1 == -z || i1 == z; -+ // if (flag || flag1) { ++ for (int z = -radius; z <= radius; z += xEdge ? 1 : radius * 2) { ++ // boolean zEdge = z == -radius || z == radius; ++ // if (xEdge || zEdge) { + if (true) { -+ // Paper end - Perf: iterate over border chunks instead of entire square chunk area - int i2 = x + spacing * i; - int i3 = y + spacing * i1; - ChunkPos potentialStructureChunk = spreadPlacement.getPotentialStructureChunk(seed, i2, i3); -@@ -311,7 +_,7 @@ ++ // Paper end - Perf: iterate over border chunks instead of entire square chunk area + int sectorX = chunkOriginX + spacing * x; + int sectorZ = chunkOriginZ + spacing * z; + ChunkPos chunkTarget = config.getPotentialStructureChunk(seed, sectorX, sectorZ); +@@ -314,7 +_,7 @@ } } -- public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) { -+ public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) { // CraftBukkit - rename - ChunkPos pos = chunk.getPos(); - if (!SharedConstants.debugVoidTerrain(pos)) { - SectionPos sectionPos = SectionPos.of(pos, level.getMinSectionY()); -@@ -382,7 +_,14 @@ - int i3 = ints[i2]; - PlacedFeature placedFeature = stepFeatureData1.features().get(i3); - Supplier supplier1 = () -> registry1.getResourceKey(placedFeature).map(Object::toString).orElseGet(placedFeature::toString); -- worldgenRandom.setFeatureSeed(l, i3, i); +- public void applyBiomeDecoration(final WorldGenLevel level, final ChunkAccess chunk, final StructureManager structureManager) { ++ public void addVanillaDecorations(final WorldGenLevel level, final ChunkAccess chunk, final StructureManager structureManager) { // CraftBukkit - rename + ChunkPos centerPos = chunk.getPos(); + if (!SharedConstants.debugVoidTerrain(centerPos)) { + SectionPos sectionPos = SectionPos.of(centerPos, level.getMinSectionY()); +@@ -388,7 +_,14 @@ + Supplier currentlyGenerating = () -> featureRegistry.getResourceKey(feature) + .map(Object::toString) + .orElseGet(feature::toString); +- random.setFeatureSeed(decorationSeed, globalIndexOfFeature, stepIndex); + // Paper start - Configurable feature seeds; change populationSeed used in random -+ long featurePopulationSeed = l; -+ final long configFeatureSeed = level.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedFeature.feature()); ++ long featurePopulationSeed = decorationSeed; ++ final long configFeatureSeed = level.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(feature.feature()); + if (configFeatureSeed != -1) { -+ featurePopulationSeed = worldgenRandom.setDecorationSeed(configFeatureSeed, blockPos.getX(), blockPos.getZ()); // See WorldgenRandom.setDecorationSeed from above ++ featurePopulationSeed = random.setDecorationSeed(configFeatureSeed, origin.getX(), origin.getZ()); // See WorldgenRandom.setDecorationSeed from above + } -+ worldgenRandom.setFeatureSeed(featurePopulationSeed, i3, i); ++ random.setFeatureSeed(featurePopulationSeed, globalIndexOfFeature, stepIndex); + // Paper end - Configurable feature seeds try { - level.setCurrentlyGenerating(supplier1); -@@ -407,6 +_,32 @@ + level.setCurrentlyGenerating(currentlyGenerating); +@@ -416,6 +_,34 @@ } } } -+ // CraftBukkit start -+ public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) { ++ // CraftBukkit start ++ public void applyBiomeDecoration(final WorldGenLevel level, final ChunkAccess chunk, final StructureManager structureManager) { + this.applyBiomeDecoration(level, chunk, structureManager, true); + } + -+ public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager, boolean addVanillaDecorations) { ++ public void applyBiomeDecoration( ++ final WorldGenLevel level, final ChunkAccess chunk, final StructureManager structureManager, final boolean addVanillaDecorations ++ ) { + if (addVanillaDecorations) { + this.addVanillaDecorations(level, chunk, structureManager); + } @@ -107,8 +111,8 @@ + // only call when a populator is present (prevents unnecessary entity conversion) + if (!world.getPopulators().isEmpty()) { + org.bukkit.craftbukkit.generator.CraftLimitedRegion limitedRegion = new org.bukkit.craftbukkit.generator.CraftLimitedRegion(level, chunk.getPos()); -+ int x = chunk.getPos().x; -+ int z = chunk.getPos().z; ++ int x = chunk.getPos().x(); ++ int z = chunk.getPos().z(); + for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) { + WorldgenRandom seededrandom = new WorldgenRandom(new net.minecraft.world.level.levelgen.LegacyRandomSource(level.getSeed())); + seededrandom.setDecorationSeed(level.getSeed(), x, z); @@ -120,29 +124,29 @@ + } + // CraftBukkit end - private static BoundingBox getWritableArea(ChunkAccess chunk) { - ChunkPos pos = chunk.getPos(); -@@ -484,7 +_,7 @@ + private static BoundingBox getWritableArea(final ChunkAccess chunk) { + ChunkPos chunkPos = chunk.getPos(); +@@ -495,7 +_,7 @@ } } -- if (structurePlacement.isStructureChunk(structureState, pos.x, pos.z)) { -+ if (structurePlacement.isStructureChunk(structureState, pos.x, pos.z, structurePlacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs - if (list.size() == 1) { +- if (featurePlacement.isStructureChunk(state, sourceChunkPos.x(), sourceChunkPos.z())) { ++ if (featurePlacement.isStructureChunk(state, sourceChunkPos.x(), sourceChunkPos.z(), featurePlacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs + if (structures.size() == 1) { this.tryGenerateStructure( - list.get(0), -@@ -579,6 +_,14 @@ - predicate + structures.get(0), +@@ -590,6 +_,14 @@ + biomePredicate ); - if (structureStart.isValid()) { + if (start.isValid()) { + // CraftBukkit start -+ BoundingBox box = structureStart.getBoundingBox(); -+ org.bukkit.event.world.AsyncStructureSpawnEvent event = new org.bukkit.event.world.AsyncStructureSpawnEvent(structureManager.level.getMinecraftWorld().getWorld(), org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), chunkPos.x, chunkPos.z); ++ BoundingBox box = start.getBoundingBox(); ++ org.bukkit.event.world.AsyncStructureSpawnEvent event = new org.bukkit.event.world.AsyncStructureSpawnEvent(structureManager.level.getMinecraftWorld().getWorld(), org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), sourceChunkPos.x(), sourceChunkPos.z()); + org.bukkit.Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return true; + } + // CraftBukkit end - structureManager.setStartForStructure(sectionPos, structure, structureStart, chunk); + structureManager.setStartForStructure(sectionPos, structure, start, centerChunk); return true; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch index 30d517aba8b1..7b2700f09563 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch @@ -7,24 +7,24 @@ + public final org.spigotmc.SpigotWorldConfig conf; // Paper - Add missing structure set seed configs public static ChunkGeneratorStructureState createForFlat( -- RandomState randomState, long levelSeed, BiomeSource biomeSource, Stream> structureSets -+ RandomState randomState, long levelSeed, BiomeSource biomeSource, Stream> structureSets, org.spigotmc.SpigotWorldConfig conf // Spigot +- final RandomState randomState, final long levelSeed, final BiomeSource biomeSource, final Stream> structureOverrides ++ final RandomState randomState, final long levelSeed, final BiomeSource biomeSource, final Stream> structureOverrides, org.spigotmc.SpigotWorldConfig conf // Spigot ) { - List> list = structureSets.filter(structureSet -> hasBiomesForStructureSet(structureSet.value(), biomeSource)).toList(); -- return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, list); -+ return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot + List> structures = structureOverrides.filter(structureSet -> hasBiomesForStructureSet(structureSet.value(), biomeSource)).toList(); +- return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, structures); ++ return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, ChunkGeneratorStructureState.injectSpigot(structures, conf), conf); // Spigot } public static ChunkGeneratorStructureState createForNormal( -- RandomState randomState, long seed, BiomeSource biomeSource, HolderLookup structureSetLookup -+ RandomState randomState, long seed, BiomeSource biomeSource, HolderLookup structureSetLookup, org.spigotmc.SpigotWorldConfig conf // Spigot +- final RandomState randomState, final long levelSeed, final BiomeSource biomeSource, final HolderLookup allStructures ++ final RandomState randomState, final long levelSeed, final BiomeSource biomeSource, final HolderLookup allStructures, org.spigotmc.SpigotWorldConfig conf // Spigot ) { - List> list = structureSetLookup.listElements() + List> structures = allStructures.listElements() .filter(structureSet -> hasBiomesForStructureSet(structureSet.value(), biomeSource)) .collect(Collectors.toUnmodifiableList()); -- return new ChunkGeneratorStructureState(randomState, biomeSource, seed, seed, list); +- return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, levelSeed, structures); - } -+ return new ChunkGeneratorStructureState(randomState, biomeSource, seed, seed, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot ++ return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, levelSeed, ChunkGeneratorStructureState.injectSpigot(structures, conf), conf); // Spigot + } + // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key + public static final class KeyedRandomSpreadStructurePlacement extends net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement { @@ -113,14 +113,14 @@ + } + // Spigot end - private static boolean hasBiomesForStructureSet(StructureSet structureSet, BiomeSource biomeSource) { - Stream> stream = structureSet.structures().stream().flatMap(structureEntry -> { -@@ -67,13 +_,14 @@ - } - - private ChunkGeneratorStructureState( -- RandomState randomState, BiomeSource biomeSource, long levelSeed, long concentricRingsSeed, List> possibleStructureSets -+ RandomState randomState, BiomeSource biomeSource, long levelSeed, long concentricRingsSeed, List> possibleStructureSets, org.spigotmc.SpigotWorldConfig conf // Paper - Add missing structure set seed configs + private static boolean hasBiomesForStructureSet(final StructureSet structureSet, final BiomeSource biomeSource) { + Stream> structureBiomes = structureSet.structures().stream().flatMap(entry -> { +@@ -71,13 +_,14 @@ + final BiomeSource biomeSource, + final long levelSeed, + final long concentricRingsSeed, +- final List> possibleStructureSets ++ final List> possibleStructureSets, org.spigotmc.SpigotWorldConfig conf // Paper - Add missing structure set seed configs ) { this.randomState = randomState; this.levelSeed = levelSeed; @@ -131,26 +131,26 @@ } public List> possibleStructureSets() { -@@ -118,7 +_,13 @@ +@@ -115,7 +_,13 @@ int spread = placement.spread(); - HolderSet holderSet = placement.preferredBiomes(); - RandomSource randomSource = RandomSource.create(); + HolderSet preferredBiomes = placement.preferredBiomes(); + RandomSource random = RandomSource.create(); + // Paper start - Add missing structure set seed configs + if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { -+ randomSource.setSeed(this.conf.strongholdSeed); ++ random.setSeed(this.conf.strongholdSeed); + } else { + // Paper end - Add missing structure set seed configs - randomSource.setSeed(this.concentricRingsSeed); + random.setSeed(this.concentricRingsSeed); + } // Paper - Add missing structure set seed configs - double d = randomSource.nextDouble() * Math.PI * 2.0; - int i = 0; - int i1 = 0; -@@ -196,7 +_,7 @@ + double angle = random.nextDouble() * Math.PI * 2.0; + int positionInCircle = 0; + int circle = 0; +@@ -193,7 +_,7 @@ - for (int i = x - range; i <= x + range; i++) { - for (int i1 = z - range; i1 <= z + range; i1++) { -- if (structurePlacement.isStructureChunk(this, i, i1)) { -+ if (structurePlacement.isStructureChunk(this, i, i1, structurePlacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs + for (int testX = sourceX - range; testX <= sourceX + range; testX++) { + for (int testZ = sourceZ - range; testZ <= sourceZ + range; testZ++) { +- if (placement.isStructureChunk(this, testX, testZ)) { ++ if (placement.isStructureChunk(this, testX, testZ, placement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs return true; } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/EmptyLevelChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/EmptyLevelChunk.java.patch index bf030502e8ce..b55910d2927c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/EmptyLevelChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/EmptyLevelChunk.java.patch @@ -12,5 +12,5 @@ + // Paper end + @Override - public @Nullable BlockState setBlockState(BlockPos pos, BlockState state, @Block.UpdateFlags int flags) { + public @Nullable BlockState setBlockState(final BlockPos pos, final BlockState state, @Block.UpdateFlags final int flags) { return null; diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/HashMapPalette.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/HashMapPalette.java.patch index f72ceacf8888..65b0eb71bf7f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/HashMapPalette.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/HashMapPalette.java.patch @@ -3,26 +3,26 @@ @@ -18,7 +_,7 @@ } - public HashMapPalette(int bits) { + public HashMapPalette(final int bits) { - this(bits, CrudeIncrementalIntIdentityHashBiMap.create(1 << bits)); + this(bits, CrudeIncrementalIntIdentityHashBiMap.create((1 << bits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap } - private HashMapPalette(int bits, CrudeIncrementalIntIdentityHashBiMap values) { + private HashMapPalette(final int bits, final CrudeIncrementalIntIdentityHashBiMap values) { @@ -34,10 +_,16 @@ - public int idFor(T state, PaletteResize resizeHandler) { - int id = this.values.getId(state); + public int idFor(final T value, final PaletteResize resizeHandler) { + int id = this.values.getId(value); if (id == -1) { -- id = this.values.add(state); +- id = this.values.add(value); - if (id >= 1 << this.bits) { + // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize + // We use size() instead of the result from add(K) + // This avoids adding another object unnecessarily + // Without this change, + 2 would be required in the constructor + if (this.values.size() >= 1 << this.bits) { - id = resizeHandler.onResize(this.bits + 1, state); + id = resizeHandler.onResize(this.bits + 1, value); + } else { -+ id = this.values.add(state); ++ id = this.values.add(value); } + // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch index 332679661db4..887a899d6af9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch @@ -12,5 +12,5 @@ + // Paper end + @Override - public FluidState getFluidState(BlockPos pos) { + public FluidState getFluidState(final BlockPos pos) { return this.wrapped.getFluidState(pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch index 4173f4e8e9fd..f060348c8a0e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -87,13 +_,21 @@ +@@ -88,13 +_,21 @@ }; private final Map tickersInLevel = Maps.newHashMap(); public boolean loaded; @@ -21,29 +21,29 @@ + boolean loadedTicketLevel; + // Paper end - public LevelChunk(Level level, ChunkPos pos) { + public LevelChunk(final Level level, final ChunkPos pos) { this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); -@@ -111,7 +_,7 @@ - @Nullable BlendingData blendingData +@@ -112,7 +_,7 @@ + final @Nullable BlendingData blendingData ) { - super(pos, data, level, level.palettedContainerFactory(), inhabitedTime, sections, blendingData); + super(pos, upgradeData, level, level.palettedContainerFactory(), inhabitedTime, sections, blendingData); - this.level = level; + this.level = (ServerLevel) level; // CraftBukkit - type this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>(); - for (Heightmap.Types types : Heightmap.Types.values()) { -@@ -163,6 +_,10 @@ - this.skyLightSources = chunk.skyLightSources; - this.setLightCorrect(chunk.isLightCorrect()); + for (Heightmap.Types type : Heightmap.Types.values()) { +@@ -164,6 +_,10 @@ + this.skyLightSources = protoChunk.skyLightSources; + this.setLightCorrect(protoChunk.isLightCorrect()); this.markUnsaved(); + this.needsDecoration = true; // CraftBukkit + // CraftBukkit start -+ this.persistentDataContainer = chunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading. ++ this.persistentDataContainer = protoChunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading. + // CraftBukkit end } - public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) { -@@ -171,6 +_,12 @@ + public void setUnsavedListener(final LevelChunk.UnsavedListener unsavedListener) { +@@ -172,6 +_,12 @@ unsavedListener.setUnsaved(this.chunkPos); } } @@ -56,8 +56,8 @@ @Override public void markUnsaved() { -@@ -204,8 +_,28 @@ - : super.getListenerRegistry(sectionY); +@@ -205,8 +_,28 @@ + : super.getListenerRegistry(section); } + // Paper start - Perf: Reduce instructions and provide final method @@ -77,7 +77,7 @@ + } + @Override - public BlockState getBlockState(BlockPos pos) { + public BlockState getBlockState(final BlockPos pos) { + if (true) { + return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); + } @@ -85,7 +85,7 @@ int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); -@@ -240,28 +_,42 @@ +@@ -241,28 +_,42 @@ } } @@ -102,47 +102,47 @@ + // Paper end + @Override - public FluidState getFluidState(BlockPos pos) { + public FluidState getFluidState(final BlockPos pos) { return this.getFluidState(pos.getX(), pos.getY(), pos.getZ()); } - public FluidState getFluidState(int x, int y, int z) { + public FluidState getFluidState(final int x, final int y, final int z) { - try { + // try { // Paper start - Perf: Optimise Chunk#getFluid int sectionIndex = this.getSectionIndex(y); if (sectionIndex >= 0 && sectionIndex < this.sections.length) { - LevelChunkSection levelChunkSection = this.sections[sectionIndex]; - if (!levelChunkSection.hasOnlyAir()) { -- return levelChunkSection.getFluidState(x & 15, y & 15, z & 15); -+ return levelChunkSection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid + LevelChunkSection currentSection = this.sections[sectionIndex]; + if (!currentSection.hasOnlyAir()) { +- return currentSection.getFluidState(x & 15, y & 15, z & 15); ++ return currentSection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid } } return Fluids.EMPTY.defaultFluidState(); + /* // Paper - Perf: Optimise Chunk#getFluid } catch (Throwable var7) { - CrashReport crashReport = CrashReport.forThrowable(var7, "Getting fluid state"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Block being got"); - crashReportCategory.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z)); - throw new ReportedException(crashReport); + CrashReport report = CrashReport.forThrowable(var7, "Getting fluid state"); + CrashReportCategory category = report.addCategory("Block being got"); + category.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z)); + throw new ReportedException(report); } + */ // Paper - Perf: Optimise Chunk#getFluid } @Override -@@ -322,7 +_,7 @@ - if (!section.getBlockState(i, i1, i2).is(block)) { +@@ -323,7 +_,7 @@ + if (!section.getBlockState(localX, localY, localZ).is(newBlock)) { return null; } else { - if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0) { -+ if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0 && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. - state.onPlace(this.level, pos, blockState, flag1); ++ if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0 && (!this.level.captureBlockStates || newBlock instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. + state.onPlace(this.level, pos, oldState, movedByPiston); } -@@ -373,7 +_,12 @@ +@@ -369,7 +_,12 @@ } - public @Nullable BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) { + public @Nullable BlockEntity getBlockEntity(final BlockPos pos, final LevelChunk.EntityCreationType creationType) { - BlockEntity blockEntity = this.blockEntities.get(pos); + // CraftBukkit start + BlockEntity blockEntity = this.level.capturedTileEntities.get(pos); @@ -151,36 +151,36 @@ + } + // CraftBukkit end if (blockEntity == null) { - CompoundTag compoundTag = this.pendingBlockEntities.remove(pos); - if (compoundTag != null) { -@@ -428,7 +_,13 @@ - BlockPos blockPos = blockEntity.getBlockPos(); - BlockState blockState = this.getBlockState(blockPos); + CompoundTag tag = this.pendingBlockEntities.remove(pos); + if (tag != null) { +@@ -424,7 +_,13 @@ + BlockPos pos = blockEntity.getBlockPos(); + BlockState blockState = this.getBlockState(pos); if (!blockState.hasBlockEntity()) { -- LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", blockEntity, blockPos, blockState); +- LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", blockEntity, pos, blockState); + // Paper start - ServerExceptionEvent + com.destroystokyo.paper.exception.ServerInternalException e = new com.destroystokyo.paper.exception.ServerInternalException( -+ "Trying to set block entity %s at position %s, but state %s does not allow it".formatted(blockEntity, blockPos, blockState) ++ "Trying to set block entity %s at position %s, but state %s does not allow it".formatted(blockEntity, pos, blockState) + ); + e.printStackTrace(); + com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e); + // Paper end - ServerExceptionEvent } else { - BlockState blockState1 = blockEntity.getBlockState(); - if (blockState != blockState1) { -@@ -475,6 +_,11 @@ - public void removeBlockEntity(BlockPos pos) { + BlockState cachedBlockState = blockEntity.getBlockState(); + if (blockState != cachedBlockState) { +@@ -471,6 +_,11 @@ + public void removeBlockEntity(final BlockPos pos) { if (this.isInLevel()) { - BlockEntity blockEntity = this.blockEntities.remove(pos); + BlockEntity removeThis = this.blockEntities.remove(pos); + // CraftBukkit start - SPIGOT-5561: Also remove from pending map + if (!this.pendingBlockEntities.isEmpty()) { + this.pendingBlockEntities.remove(pos); + } + // CraftBukkit end - if (blockEntity != null) { + if (removeThis != null) { if (this.level instanceof ServerLevel serverLevel) { - this.removeGameEventListener(blockEntity, serverLevel); -@@ -518,6 +_,65 @@ + this.removeGameEventListener(removeThis, serverLevel); +@@ -514,6 +_,65 @@ } } @@ -206,7 +206,7 @@ + random.setSeed(this.level.getSeed()); + long xRand = random.nextLong() / 2L * 2L + 1L; + long zRand = random.nextLong() / 2L * 2L + 1L; -+ random.setSeed((long) this.chunkPos.x * xRand + (long) this.chunkPos.z * zRand ^ this.level.getSeed()); ++ random.setSeed((long)this.chunkPos.x() * xRand + (long)this.chunkPos.z() * zRand ^ this.level.getSeed()); + + org.bukkit.World world = this.level.getWorld(); + if (world != null) { @@ -246,7 +246,7 @@ public boolean isEmpty() { return false; } -@@ -756,23 +_,24 @@ +@@ -752,23 +_,24 @@ if (this.blockEntity.getType().isValid(blockState)) { this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity); this.loggedInvalidBlockState = false; @@ -269,12 +269,12 @@ + // Paper end - Remove the Block Entity if it's invalid } - profilerFiller.pop(); + profiler.pop(); } catch (Throwable var5) { -- CrashReport crashReport = CrashReport.forThrowable(var5, "Ticking block entity"); -- CrashReportCategory crashReportCategory = crashReport.addCategory("Block entity being ticked"); -- this.blockEntity.fillCrashReportCategory(crashReportCategory); -- throw new ReportedException(crashReport); +- CrashReport report = CrashReport.forThrowable(var5, "Ticking block entity"); +- CrashReportCategory category = report.addCategory("Block entity being ticked"); +- this.blockEntity.fillCrashReportCategory(category); +- throw new ReportedException(report); + // Paper start - Prevent block entity and entity crashes + final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); + net.minecraft.server.MinecraftServer.LOGGER.error(msg, var5); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch index 1c1f58b5ab2f..9777946eba03 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch @@ -1,40 +1,41 @@ --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -14,11 +_,11 @@ +@@ -15,12 +_,12 @@ public static final int SECTION_HEIGHT = 16; public static final int SECTION_SIZE = 4096; public static final int BIOME_CONTAINER_BITS = 2; - private short nonEmptyBlockCount; + short nonEmptyBlockCount; // Paper - package private + private short fluidCount; private short tickingBlockCount; private short tickingFluidCount; public final PalettedContainer states; - private PalettedContainerRO> biomes; + private PalettedContainer> biomes; // CraftBukkit - read/write - private LevelChunkSection(LevelChunkSection section) { - this.nonEmptyBlockCount = section.nonEmptyBlockCount; -@@ -28,7 +_,7 @@ - this.biomes = section.biomes.copy(); + private LevelChunkSection(final LevelChunkSection source) { + this.nonEmptyBlockCount = source.nonEmptyBlockCount; +@@ -31,7 +_,7 @@ + this.biomes = source.biomes.copy(); } -- public LevelChunkSection(PalettedContainer states, PalettedContainerRO> biomes) { -+ public LevelChunkSection(PalettedContainer states, PalettedContainer> biomes) { // CraftBukkit - read/write +- public LevelChunkSection(final PalettedContainer states, final PalettedContainerRO> biomes) { ++ public LevelChunkSection(final PalettedContainer states, final PalettedContainer> biomes) { // CraftBukkit - read/write this.states = states; this.biomes = biomes; this.recalcBlockCounts(); -@@ -44,7 +_,7 @@ +@@ -47,7 +_,7 @@ } - public FluidState getFluidState(int x, int y, int z) { -- return this.states.get(x, y, z).getFluidState(); -+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise LevelChunk#getFluidState; diff on change - we expect this to be effectively just get(x, y, z).getFluidState(). If this changes we need to check other patches that use BlockBehaviour#getFluidState. + public FluidState getFluidState(final int sectionX, final int sectionY, final int sectionZ) { +- return this.states.get(sectionX, sectionY, sectionZ).getFluidState(); ++ return this.states.get(sectionX, sectionY, sectionZ).getFluidState(); // Paper - Perf: Optimise LevelChunk#getFluidState; diff on change - we expect this to be effectively just get(x, y, z).getFluidState(). If this changes we need to check other patches that use BlockBehaviour#getFluidState. } public void acquire() { -@@ -181,6 +_,11 @@ - public Holder getNoiseBiome(int x, int y, int z) { - return this.biomes.get(x, y, z); +@@ -203,6 +_,11 @@ + public Holder getNoiseBiome(final int quartX, final int quartY, final int quartZ) { + return this.biomes.get(quartX, quartY, quartZ); } + // CraftBukkit start + public void setBiome(int x, int y, int z, Holder biome) { @@ -42,5 +43,5 @@ + } + // CraftBukkit end - public void fillBiomesFromNoise(BiomeResolver biomeResolver, Climate.Sampler climateSampler, int x, int y, int z) { - PalettedContainer> palettedContainer = this.biomes.recreate(); + public void fillBiomesFromNoise( + final BiomeResolver biomeResolver, final Climate.Sampler sampler, final int quartMinX, final int quartMinY, final int quartMinZ diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch index f8ed89adb41c..072c43a99a1a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch @@ -17,58 +17,58 @@ + // this.threadingDetector.checkAndUnlock(); // Paper - disable this - use proper synchronization } - public static Codec> codecRW(Codec valueCodec, Strategy strategy, T defaultValue) { -@@ -93,7 +_,7 @@ + public static Codec> codecRW(final Codec elementCodec, final Strategy strategy, final T defaultValue) { +@@ -94,7 +_,7 @@ } @Override -- public int onResize(int bits, T addedValue) { -+ public synchronized int onResize(int bits, T addedValue) { // Paper - synchronize - PalettedContainer.Data data = this.data; - PalettedContainer.Data data1 = this.createOrReuseData(data, bits); - data1.copyFrom(data.palette, data.storage); -@@ -101,7 +_,7 @@ - return data1.palette.idFor(addedValue, PaletteResize.noResizeExpected()); +- public int onResize(final int bits, final T lastAddedValue) { ++ public synchronized int onResize(final int bits, final T lastAddedValue) { // Paper - synchronize + PalettedContainer.Data oldData = this.data; + PalettedContainer.Data newData = this.createOrReuseData(oldData, bits); + newData.copyFrom(oldData.palette, oldData.storage); +@@ -102,7 +_,7 @@ + return newData.palette.idFor(lastAddedValue, PaletteResize.noResizeExpected()); } -- public T getAndSet(int x, int y, int z, T state) { -+ public synchronized T getAndSet(int x, int y, int z, T state) { // Paper - synchronize +- public T getAndSet(final int x, final int y, final int z, final T value) { ++ public synchronized T getAndSet(final int x, final int y, final int z, final T value) { // Paper - synchronize this.acquire(); Object var5; -@@ -124,7 +_,7 @@ - return this.data.palette.valueFor(andSet); +@@ -125,7 +_,7 @@ + return this.data.palette.valueFor(oldId); } -- public void set(int x, int y, int z, T state) { -+ public synchronized void set(int x, int y, int z, T state) { // Paper - synchronize +- public void set(final int x, final int y, final int z, final T value) { ++ public synchronized void set(final int x, final int y, final int z, final T value) { // Paper - synchronize this.acquire(); try { -@@ -157,7 +_,7 @@ - set.forEach(id -> consumer.accept(palette.valueFor(id))); +@@ -158,7 +_,7 @@ + allExistingEntries.forEach(state -> consumer.accept(palette.valueFor(state))); } -- public void read(FriendlyByteBuf buffer) { -+ public synchronized void read(FriendlyByteBuf buffer) { // Paper - synchronize +- public void read(final FriendlyByteBuf buffer) { ++ public synchronized void read(final FriendlyByteBuf buffer) { // Paper - synchronize this.acquire(); try { -@@ -172,7 +_,7 @@ +@@ -173,7 +_,7 @@ } @Override -- public void write(FriendlyByteBuf buffer) { -+ public synchronized void write(FriendlyByteBuf buffer) { // Paper - synchronize +- public void write(final FriendlyByteBuf buffer) { ++ public synchronized void write(final FriendlyByteBuf buffer) { // Paper - synchronize this.acquire(); try { -@@ -226,7 +_,7 @@ +@@ -227,7 +_,7 @@ } @Override -- public PalettedContainerRO.PackedData pack(Strategy strategy) { -+ public synchronized PalettedContainerRO.PackedData pack(Strategy strategy) { // Paper - synchronize +- public PalettedContainerRO.PackedData pack(final Strategy strategy) { ++ public synchronized PalettedContainerRO.PackedData pack(final Strategy strategy) { // Paper - synchronize this.acquire(); PalettedContainerRO.PackedData var14; diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainerFactory.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainerFactory.java.patch index e7c119b53452..7338d09abd81 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainerFactory.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainerFactory.java.patch @@ -6,13 +6,13 @@ Codec>> biomeContainerCodec + , Codec>> biomeContainerRWCodec // Paper ) { - public static PalettedContainerFactory create(RegistryAccess registryAccess) { - Strategy strategy = Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY); + public static PalettedContainerFactory create(final RegistryAccess registries) { + Strategy blockStateStrategy = Strategy.createForBlockStates(Block.BLOCK_STATE_REGISTRY); @@ -32,6 +_,7 @@ - strategy1, - orThrow, - PalettedContainer.codecRO(registry.holderByNameCodec(), strategy1, orThrow) -+ , PalettedContainer.codecRW(registry.holderByNameCodec(), strategy1, orThrow) // Paper + biomeStrategy, + defaultBiome, + PalettedContainer.codecRO(biomes.holderByNameCodec(), biomeStrategy, defaultBiome) ++ , PalettedContainer.codecRW(biomes.holderByNameCodec(), biomeStrategy, defaultBiome) // Paper ); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch index f0f46aee2a6d..0b28e108703a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/chunk/ProtoChunk.java +++ b/net/minecraft/world/level/chunk/ProtoChunk.java @@ -90,14 +_,31 @@ - return new ChunkAccess.PackedTicks(this.blockTicks.pack(gameTime), this.fluidTicks.pack(gameTime)); + return new ChunkAccess.PackedTicks(this.blockTicks.pack(currentTick), this.fluidTicks.pack(currentTick)); } + // Paper start - If loaded util @@ -17,7 +17,7 @@ + // Paper end + @Override - public BlockState getBlockState(BlockPos pos) { + public BlockState getBlockState(final BlockPos pos) { - int y = pos.getY(); + // Paper start + return this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch index e11eae4bb003..08fdc2236b4c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/UpgradeData.java.patch @@ -23,7 +23,7 @@ + } + // Paper end - filter out relocated neighbour ticks + - public void upgrade(LevelChunk chunk) { + public void upgrade(final LevelChunk chunk) { this.upgradeInside(chunk); @@ -94,6 +_,10 @@ @@ -35,13 +35,13 @@ + filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks); + // Paper end - filter out relocated neighbour ticks Level level = chunk.getLevel(); - this.neighborBlockTicks.forEach(savedTick -> { - Block block = savedTick.type() == Blocks.AIR ? level.getBlockState(savedTick.pos()).getBlock() : savedTick.type(); + this.neighborBlockTicks.forEach(tick -> { + Block type = tick.type() == Blocks.AIR ? level.getBlockState(tick.pos()).getBlock() : tick.type(); @@ -103,6 +_,7 @@ - Fluid fluid = savedTick.type() == Fluids.EMPTY ? level.getFluidState(savedTick.pos()).getType() : savedTick.type(); - level.scheduleTick(savedTick.pos(), fluid, savedTick.delay(), savedTick.priority()); + Fluid type = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type(); + level.scheduleTick(tick.pos(), type, tick.delay(), tick.priority()); }); + UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised - CHUNKY_FIXERS.forEach(blockFixer -> blockFixer.processChunk(level)); + CHUNKY_FIXERS.forEach(fixer -> fixer.processChunk(level)); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java.patch index c329cff10fc1..adbcbbae2af5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +++ b/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java @@ -41,7 +_,7 @@ - WorldGenContext worldGenContext, ChunkStep step, StaticCache2D cache, ChunkAccess chunk + final WorldGenContext context, final ChunkStep step, final StaticCache2D chunks, final ChunkAccess chunk ) { - ServerLevel serverLevel = worldGenContext.level(); -- if (serverLevel.getServer().getWorldData().worldGenOptions().generateStructures()) { -+ if (serverLevel.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit - worldGenContext.generator() + ServerLevel level = context.level(); +- if (level.getServer().getWorldGenSettings().options().generateStructures()) { ++ if (level.worldDataAndGenSettings.genSettings().options().generateStructures()) { // CraftBukkit + context.generator() .createStructures( - serverLevel.registryAccess(), -@@ -211,7 +_,51 @@ + level.registryAccess(), +@@ -210,7 +_,51 @@ - public static void postLoadProtoChunk(ServerLevel level, ValueInput.ValueInputList input) { - if (!input.isEmpty()) { -- level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(input, level, EntitySpawnReason.LOAD)); + public static void postLoadProtoChunk(final ServerLevel level, final ValueInput.ValueInputList entities) { + if (!entities.isEmpty()) { +- level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, level, EntitySpawnReason.LOAD)); - } - } + // Paper start - duplicate uuid resolving -+ level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(input, level, EntitySpawnReason.LOAD).filter((entity) -> { ++ level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, level, EntitySpawnReason.LOAD).filter((entity) -> { + return !checkDupeUUID(level, entity); + })); + // Paper end - duplicate uuid resolving diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch index b04f2e617633..054f739c75d9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -46,7 +_,7 @@ +@@ -47,7 +_,7 @@ protected final RegionBitmap usedSectors = new RegionBitmap(); - public RegionFile(RegionStorageInfo info, Path path, Path externalFileDir, boolean sync) throws IOException { + public RegionFile(final RegionStorageInfo info, final Path path, final Path externalFileDir, final boolean sync) throws IOException { - this(info, path, externalFileDir, RegionFileVersion.getSelected(), sync); + this(info, path, externalFileDir, RegionFileVersion.getCompressionFormat(), sync); // Paper - Configurable region compression format } - public RegionFile(RegionStorageInfo info, Path path, Path externalFileDir, RegionFileVersion version, boolean sync) throws IOException { -@@ -82,6 +_,14 @@ - if (i2 != 0) { - int sectorNumber = getSectorNumber(i2); - int numSectors = getNumSectors(i2); + public RegionFile(final RegionStorageInfo info, final Path path, final Path externalFileDir, final RegionFileVersion version, final boolean sync) throws IOException { +@@ -83,6 +_,14 @@ + if (offset != 0) { + int sectorNumber = getSectorNumber(offset); + int numSectors = getNumSectors(offset); + // Spigot start + if (numSectors == 255) { + // We're maxed out, so we need to read the proper length from the section @@ -22,9 +22,9 @@ + } + // Spigot end if (sectorNumber < 2) { - LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i1, sectorNumber); - this.offsets.put(i1, 0); -@@ -116,6 +_,13 @@ + LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber); + this.offsets.put(i, 0); +@@ -117,6 +_,13 @@ } else { int sectorNumber = getSectorNumber(offset); int numSectors = getNumSectors(offset); @@ -35,10 +35,10 @@ + numSectors = (realLen.getInt(0) + 4) / 4096 + 1; + } + // Spigot end - int i = numSectors * 4096; - ByteBuffer byteBuffer = ByteBuffer.allocate(i); - this.file.read(byteBuffer, sectorNumber * 4096); -@@ -257,6 +_,7 @@ + int sectorsLength = numSectors * 4096; + ByteBuffer buffer = ByteBuffer.allocate(sectorsLength); + this.file.read(buffer, sectorNumber * 4096); +@@ -258,6 +_,7 @@ return true; } } catch (IOException var9) { @@ -46,10 +46,10 @@ return false; } } -@@ -328,6 +_,11 @@ - try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { - chunkData.position(5); - fileChannel.write(chunkData); +@@ -329,6 +_,11 @@ + try (FileChannel extFile = FileChannel.open(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { + data.position(5); + extFile.write(data); + // Paper start - ServerExceptionEvent + } catch (Throwable throwable) { + com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); @@ -57,4 +57,4 @@ + // Paper end - ServerExceptionEvent } - return () -> Files.move(path, externalChunkFile, StandardCopyOption.REPLACE_EXISTING); + return () -> Files.move(tmpPath, path, StandardCopyOption.REPLACE_EXISTING); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch index 3d3404cdedc8..9bda26ffe55c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch @@ -4,12 +4,12 @@ this.info = info; } -- private RegionFile getRegionFile(ChunkPos chunkPos) throws IOException { -+ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit - long packedChunkPos = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()); - RegionFile regionFile = this.regionCache.getAndMoveToFirst(packedChunkPos); - if (regionFile != null) { - return regionFile; +- private RegionFile getRegionFile(final ChunkPos pos) throws IOException { ++ @org.jetbrains.annotations.Contract("_, false -> !null") private @Nullable RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit + long key = ChunkPos.pack(pos.getRegionX(), pos.getRegionZ()); + RegionFile region = this.regionCache.getAndMoveToFirst(key); + if (region != null) { + return region; } else { - if (this.regionCache.size() >= 256) { + if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - Sanitise RegionFileCache and make configurable @@ -17,45 +17,45 @@ } FileUtil.createDirectoriesSafe(this.folder); - Path path = this.folder.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca"); -+ if (existingOnly && !java.nio.file.Files.exists(path)) return null; // CraftBukkit - RegionFile regionFile1 = new RegionFile(this.info, path, this.folder, this.sync); - this.regionCache.putAndMoveToFirst(packedChunkPos, regionFile1); - return regionFile1; + Path file = this.folder.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); ++ if (existingOnly && !java.nio.file.Files.exists(file)) return null; // CraftBukkit + RegionFile newRegion = new RegionFile(this.info, file, this.folder, this.sync); + this.regionCache.putAndMoveToFirst(key, newRegion); + return newRegion; @@ -48,7 +_,12 @@ } - public @Nullable CompoundTag read(ChunkPos chunkPos) throws IOException { -- RegionFile regionFile = this.getRegionFile(chunkPos); + public @Nullable CompoundTag read(final ChunkPos pos) throws IOException { +- RegionFile region = this.getRegionFile(pos); + // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing -+ RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ if (regionFile == null) { ++ RegionFile region = this.getRegionFile(pos, true); ++ if (region == null) { + return null; + } + // CraftBukkit end CompoundTag var4; - try (DataInputStream chunkDataInputStream = regionFile.getChunkDataInputStream(chunkPos)) { + try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { @@ -63,7 +_,12 @@ } - public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException { -- RegionFile regionFile = this.getRegionFile(chunkPos); + public void scanChunk(final ChunkPos pos, final StreamTagVisitor scanner) throws IOException { +- RegionFile region = this.getRegionFile(pos); + // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing -+ RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ if (regionFile == null) { ++ RegionFile region = this.getRegionFile(pos, true); ++ if (region == null) { + return; + } + // CraftBukkit end - try (DataInputStream chunkDataInputStream = regionFile.getChunkDataInputStream(chunkPos)) { - if (chunkDataInputStream != null) { + try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { + if (regionChunkInputStream != null) { @@ -74,7 +_,7 @@ - protected void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { + protected void write(final ChunkPos pos, final @Nullable CompoundTag value) throws IOException { if (!SharedConstants.DEBUG_DONT_SAVE_WORLD) { -- RegionFile regionFile = this.getRegionFile(chunkPos); -+ RegionFile regionFile = this.getRegionFile(chunkPos, false); // CraftBukkit - if (chunkData == null) { - regionFile.clear(chunkPos); +- RegionFile region = this.getRegionFile(pos); ++ RegionFile region = this.getRegionFile(pos, false); // CraftBukkit + if (value == null) { + region.clear(pos); } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileVersion.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileVersion.java.patch index 26636eb668ec..56db01d59599 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileVersion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileVersion.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java -@@ -60,6 +_,16 @@ +@@ -49,6 +_,16 @@ private final RegionFileVersion.StreamWrapper inputWrapper; private final RegionFileVersion.StreamWrapper outputWrapper; @@ -15,5 +15,5 @@ + } + // Paper end - Configurable region compression format private RegionFileVersion( - int id, - @Nullable String optionName, + final int id, + final @Nullable String optionName, diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch index 29cbf85f57fb..803a761358c2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch @@ -8,7 +8,7 @@ ) { private static final Codec>> BLOCK_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.BLOCK.byNameCodec()).listOf(); private static final Codec>> FLUID_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.FLUID.byNameCodec()).listOf(); -@@ -107,11 +_,37 @@ +@@ -107,13 +_,39 @@ public static final String BLOCK_LIGHT_TAG = "BlockLight"; public static final String SKY_LIGHT_TAG = "SkyLight"; @@ -30,64 +30,66 @@ + private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion"); + // Paper end - Do not let the server load chunks from newer versions + - public static SerializableChunkData parse(LevelHeightAccessor level, PalettedContainerFactory containerFactory, CompoundTag tag) { - if (tag.getString("Status").isEmpty()) { + public static SerializableChunkData parse( + final LevelHeightAccessor levelHeight, final PalettedContainerFactory containerFactory, final CompoundTag chunkData + ) { + if (chunkData.getString("Status").isEmpty()) { return null; } else { -- ChunkPos chunkPos = new ChunkPos(tag.getIntOr("xPos", 0), tag.getIntOr("zPos", 0)); +- ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); + // Paper start - Do not let the server load chunks from newer versions -+ tag.getInt("DataVersion").ifPresent(dataVersion -> { ++ chunkData.getInt("DataVersion").ifPresent(dataVersion -> { + if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { + new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace(); + System.exit(1); + } + }); + // Paper end - Do not let the server load chunks from newer versions -+ ChunkPos chunkPos = new ChunkPos(tag.getIntOr("xPos", 0), tag.getIntOr("zPos", 0)); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate - long longOr = tag.getLongOr("LastUpdate", 0L); - long longOr1 = tag.getLongOr("InhabitedTime", 0L); - ChunkStatus chunkStatus = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); -@@ -150,7 +_,7 @@ - CompoundTag compoundOrEmpty = tag.getCompoundOrEmpty("structures"); - ListTag listOrEmpty1 = tag.getListOrEmpty("sections"); - List list5 = new ArrayList<>(listOrEmpty1.size()); -- Codec>> codec = containerFactory.biomeContainerCodec(); -+ Codec>> codec = containerFactory.biomeContainerRWCodec(); // CraftBukkit - read/write - Codec> codec1 = containerFactory.blockStatesContainerCodec(); ++ ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate + long lastUpdateTime = chunkData.getLongOr("LastUpdate", 0L); + long inhabitedTime = chunkData.getLongOr("InhabitedTime", 0L); + ChunkStatus status = chunkData.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); +@@ -152,7 +_,7 @@ + CompoundTag structureData = chunkData.getCompoundOrEmpty("structures"); + ListTag sectionTags = chunkData.getListOrEmpty("sections"); + List sectionData = new ArrayList<>(sectionTags.size()); +- Codec>> biomesCodec = containerFactory.biomeContainerCodec(); ++ Codec>> biomesCodec = containerFactory.biomeContainerRWCodec(); // CraftBukkit - read/write + Codec> blockStatesCodec = containerFactory.blockStatesContainerCodec(); - for (int i2 = 0; i2 < listOrEmpty1.size(); i2++) { -@@ -167,7 +_,7 @@ + for (int i = 0; i < sectionTags.size(); i++) { +@@ -169,7 +_,7 @@ .getOrThrow(SerializableChunkData.ChunkReadException::new) ) .orElseGet(containerFactory::createForBlockStates); -- PalettedContainerRO> palettedContainerRo = compoundTag.getCompound("biomes") -+ PalettedContainer> palettedContainerRo = compoundTag.getCompound("biomes") // CraftBukkit - read/write +- PalettedContainerRO> biomes = sectionTag.getCompound("biomes") ++ PalettedContainer> biomes = sectionTag.getCompound("biomes") // CraftBukkit - read/write .map( - compoundTag1 -> codec.parse(NbtOps.INSTANCE, compoundTag1) - .promotePartial(string -> logErrors(chunkPos, byteOr, string)) -@@ -204,6 +_,7 @@ - list3, - list4, - compoundOrEmpty -+ , tag.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues + container -> biomesCodec.parse(NbtOps.INSTANCE, container) + .promotePartial(msg -> logErrors(chunkPos, y, msg)) +@@ -206,6 +_,7 @@ + entities, + blockEntities, + structureData ++ , chunkData.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues ); } } -@@ -288,6 +_,12 @@ +@@ -283,6 +_,12 @@ } } + // CraftBukkit start - load chunk persistent data from nbt - SPIGOT-6814: Already load PDC here to account for 1.17 to 1.18 chunk upgrading. + if (this.persistentDataContainer instanceof CompoundTag compoundTag) { -+ chunkAccess.persistentDataContainer.putAll(compoundTag); ++ chunk.persistentDataContainer.putAll(compoundTag); + } + // CraftBukkit end + - chunkAccess.setLightCorrect(this.lightCorrect); - EnumSet set = EnumSet.noneOf(Heightmap.Types.class); + chunk.setLightCorrect(this.lightCorrect); + EnumSet toPrime = EnumSet.noneOf(Heightmap.Types.class); -@@ -394,6 +_,12 @@ - CompoundTag compoundTag = packStructureData( +@@ -389,6 +_,12 @@ + CompoundTag structureData = packStructureData( StructurePieceSerializationContext.fromLevel(level), pos, chunk.getAllStarts(), chunk.getAllReferences() ); + // CraftBukkit start - store chunk persistent data in nbt @@ -99,36 +101,36 @@ return new SerializableChunkData( level.palettedContainerFactory(), pos, -@@ -413,6 +_,7 @@ - list2, - list1, - compoundTag +@@ -408,6 +_,7 @@ + entities, + blockEntities, + structureData + , persistentDataContainer // CraftBukkit - persistentDataContainer ); } } -@@ -480,6 +_,11 @@ - this.heightmaps.forEach((types, longs) -> compoundTag2.put(types.getSerializationKey(), new LongArrayTag(longs))); - compoundTag.put("Heightmaps", compoundTag2); - compoundTag.put("structures", this.structureData); +@@ -475,6 +_,11 @@ + this.heightmaps.forEach((type, data) -> heightmapsTag.put(type.getSerializationKey(), new LongArrayTag(data))); + tag.put("Heightmaps", heightmapsTag); + tag.put("structures", this.structureData); + // CraftBukkit start - store chunk persistent data in nbt + if (this.persistentDataContainer != null) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading. -+ compoundTag.put("ChunkBukkitValues", this.persistentDataContainer); ++ tag.put("ChunkBukkitValues", this.persistentDataContainer); + } + // CraftBukkit end - return compoundTag; + return tag; } -@@ -560,6 +_,12 @@ +@@ -558,6 +_,12 @@ } else { - StructureStart structureStart = StructureStart.loadStaticStart(context, compoundOrEmpty.getCompoundOrEmpty(string), seed); - if (structureStart != null) { + StructureStart start = StructureStart.loadStaticStart(context, startsTag.getCompoundOrEmpty(key), seed); + if (start != null) { + // CraftBukkit start - load persistent data for structure start -+ net.minecraft.nbt.Tag persistentBase = compoundOrEmpty.getCompoundOrEmpty(string).get("StructureBukkitValues"); ++ net.minecraft.nbt.Tag persistentBase = startsTag.getCompoundOrEmpty(key).get("StructureBukkitValues"); + if (persistentBase instanceof CompoundTag compoundTag) { -+ structureStart.persistentDataContainer.putAll(compoundTag); ++ start.persistentDataContainer.putAll(compoundTag); + } + // CraftBukkit end - map.put(structure, structureStart); + outmap.put(startFeature, start); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch index e9b4c4a5a21e..4b3e57efc5b0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch @@ -1,66 +1,49 @@ --- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -@@ -51,19 +_,47 @@ +@@ -44,7 +_,19 @@ } - public CompletableFuture write(ChunkPos chunkPos, Supplier data) { + public CompletableFuture write(final ChunkPos pos, final Supplier supplier) { +- return this.worker.store(pos, supplier); + // Paper start - guard against possible chunk pos desync + final Supplier guardedPosCheck = () -> { -+ CompoundTag nbt = data.get(); ++ final CompoundTag nbt = supplier.get(); + final boolean chunkStorage = this.dataFixType == net.minecraft.util.datafix.DataFixTypes.CHUNK; -+ if (chunkStorage && nbt != null && !chunkPos.equals(SerializableChunkData.getChunkCoordinate(nbt))) { -+ final String world = (SimpleRegionStorage.this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) SimpleRegionStorage.this).level.getWorld().getName() : null; -+ throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + chunkPos ++ if (chunkStorage && nbt != null && !pos.equals(SerializableChunkData.getChunkCoordinate(nbt))) { ++ final String world = (this instanceof net.minecraft.server.level.ChunkMap chunkMap) ? chunkMap.level.getWorld().getName() : null; ++ throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos + + " but compound says coordinate is " + SerializableChunkData.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world))); + } + return nbt; + }; ++ return this.worker.store(pos, guardedPosCheck); + // Paper end - guard against possible chunk pos desync - this.markChunkDone(chunkPos); -- return this.worker.store(chunkPos, data); -+ return this.worker.store(chunkPos, guardedPosCheck); // Paper - guard against possible chunk pos desync } -- public CompoundTag upgradeChunkTag(CompoundTag tag, int fallbackVersion, @Nullable CompoundTag contextTag) { -+ public CompoundTag upgradeChunkTag(CompoundTag tag, int fallbackVersion, @Nullable CompoundTag contextTag, net.minecraft.world.level.@Nullable LevelAccessor levelAccessor) { // CraftBukkit - int dataVersion = NbtUtils.getDataVersion(tag, fallbackVersion); - if (dataVersion == SharedConstants.getCurrentVersion().dataVersion().version()) { - return tag; + public CompoundTag upgradeChunkTag(CompoundTag chunkTag, final int defaultVersion, final @Nullable CompoundTag dataFixContextTag, final int targetVersion) { +@@ -53,8 +_,25 @@ + return chunkTag; } else { try { - tag = this.legacyFixer.get().applyFix(tag); + // Spigot start - SPIGOT-6806: Quick and dirty way to prevent below zero generation in old chunks, by setting the status to heightmap instead of empty + boolean stopBelowZero = false; + final boolean chunkStorage = this.dataFixType == net.minecraft.util.datafix.DataFixTypes.CHUNK; + if (chunkStorage) { -+ boolean belowZeroGenerationInExistingChunks = (levelAccessor != null) ? ((net.minecraft.server.level.ServerLevel) levelAccessor).spigotConfig.belowZeroGenerationInExistingChunks : org.spigotmc.SpigotConfig.belowZeroGenerationInExistingChunks; -+ -+ if (dataVersion <= 2730 && !belowZeroGenerationInExistingChunks) { -+ stopBelowZero = "full".equals(tag.getCompound("Level").flatMap(l -> l.getString("Status")).orElse(null)); ++ final boolean belowZeroGenerationInExistingChunks = (this instanceof net.minecraft.server.level.ChunkMap chunkMap) ++ ? chunkMap.level.spigotConfig.belowZeroGenerationInExistingChunks ++ : org.spigotmc.SpigotConfig.belowZeroGenerationInExistingChunks; ++ if (version <= 2730 && !belowZeroGenerationInExistingChunks) { ++ stopBelowZero = "full".equals(chunkTag.getCompound("Level").flatMap(level -> level.getString("Status")).orElse(null)); + } + } + // Spigot end - injectDatafixingContext(tag, contextTag); - tag = this.dataFixType.updateToCurrentVersion(this.fixerUpper, tag, Math.max(this.legacyFixer.get().targetDataVersion(), dataVersion)); + injectDatafixingContext(chunkTag, dataFixContextTag); + chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion); + // Spigot start + if (stopBelowZero) { -+ tag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); ++ chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); + } + // Spigot end - removeDatafixingContext(tag); - NbtUtils.addCurrentDataVersion(tag); - return tag; -@@ -77,11 +_,11 @@ - } - - public CompoundTag upgradeChunkTag(CompoundTag tag, int version) { -- return this.upgradeChunkTag(tag, version, null); -+ return this.upgradeChunkTag(tag, version, null, null); // CraftBukkit - } - - public Dynamic upgradeChunkTag(Dynamic tag, int version) { -- return new Dynamic<>(tag.getOps(), this.upgradeChunkTag((CompoundTag)tag.getValue(), version, null)); -+ return new Dynamic<>(tag.getOps(), this.upgradeChunkTag((CompoundTag)tag.getValue(), version, null, null)); // CraftBukkit - } - - public static void injectDatafixingContext(CompoundTag tag, @Nullable CompoundTag contextTag) { + removeDatafixingContext(chunkTag); + NbtUtils.addDataVersion(chunkTag, targetVersion); + return chunkTag; diff --git a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnAnimation.java.patch b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnAnimation.java.patch deleted file mode 100644 index a5dfcd6e9ec4..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnAnimation.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/level/dimension/end/DragonRespawnAnimation.java -+++ b/net/minecraft/world/level/dimension/end/DragonRespawnAnimation.java -@@ -91,7 +_,7 @@ - for (EndCrystal endCrystal : crystals) { - endCrystal.setBeamTarget(null); - level.explode(endCrystal, endCrystal.getX(), endCrystal.getY(), endCrystal.getZ(), 6.0F, Level.ExplosionInteraction.NONE); -- endCrystal.discard(); -+ endCrystal.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause - } - } else if (ticks >= 80) { - level.levelEvent(LevelEvent.ANIMATION_DRAGON_SUMMON_ROAR, new BlockPos(0, 128, 0), 0); diff --git a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnStage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnStage.java.patch new file mode 100644 index 000000000000..c048133ab36a --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/DragonRespawnStage.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/dimension/end/DragonRespawnStage.java ++++ b/net/minecraft/world/level/dimension/end/DragonRespawnStage.java +@@ -91,7 +_,7 @@ + for (EndCrystal crystal : crystals) { + crystal.setBeamTarget(null); + level.explode(crystal, crystal.getX(), crystal.getY(), crystal.getZ(), 6.0F, Level.ExplosionInteraction.NONE); +- crystal.discard(); ++ crystal.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause + } + } else if (time >= 80) { + level.levelEvent(LevelEvent.ANIMATION_DRAGON_SUMMON_ROAR, new BlockPos(0, 128, 0), 0); diff --git a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch deleted file mode 100644 index 210efbcaf8ab..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch +++ /dev/null @@ -1,195 +0,0 @@ ---- a/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -70,8 +_,9 @@ - private static final int GATEWAY_DISTANCE = 96; - public static final int DRAGON_SPAWN_Y = 128; - private final Predicate validPlayer; -+ private static final Component DEFAULT_BOSS_EVENT_NAME = Component.translatable("entity.minecraft.ender_dragon"); // Paper - reset EnderDragon boss event name - public final ServerBossEvent dragonEvent = (ServerBossEvent)new ServerBossEvent( -- Component.translatable("entity.minecraft.ender_dragon"), BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS -+ DEFAULT_BOSS_EVENT_NAME, BossEvent.BossBarColor.PINK, BossEvent.BossBarOverlay.PROGRESS // Paper - reset EnderDragon boss event name - ) - .setPlayBossMusic(true) - .setCreateWorldFog(true); -@@ -108,7 +_,12 @@ - if (data.isRespawning) { - this.respawnStage = DragonRespawnAnimation.START; - } -- -+ // Paper start - Add config to disable ender dragon legacy check -+ if (data == EndDragonFight.Data.DEFAULT && !level.paperConfig().entities.spawning.scanForLegacyEnderDragon) { -+ this.needsStateScanning = false; -+ this.dragonKilled = true; -+ } -+ // Paper end - Add config to disable ender dragon legacy check - this.portalLocation = data.exitPortalLocation.orElse(null); - this.gateways.addAll(data.gateways.orElseGet(() -> { - ObjectArrayList list = new ObjectArrayList<>(ContiguousSet.create(Range.closedOpen(0, 20), DiscreteDomain.integers())); -@@ -205,9 +_,9 @@ - this.dragonUUID = enderDragon.getUUID(); - LOGGER.info("Found that there's a dragon still alive ({})", enderDragon); - this.dragonKilled = false; -- if (!hasActiveExitPortal) { -+ if (!hasActiveExitPortal && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { // Paper - Toggle for removing existing dragon - LOGGER.info("But we didn't have a portal, let's remove it."); -- enderDragon.discard(); -+ enderDragon.discard(null); // CraftBukkit - add Bukkit remove cause - this.dragonUUID = null; - } - } -@@ -361,12 +_,22 @@ - this.dragonEvent.setVisible(false); - this.spawnExitPortal(true); - this.spawnNewGateway(); -- if (!this.previouslyKilled) { -- this.level -- .setBlockAndUpdate( -- this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), -- Blocks.DRAGON_EGG.defaultBlockState() -- ); -+ // Paper start - Add DragonEggFormEvent -+ BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)); -+ org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition); -+ eggState.setData(Blocks.DRAGON_EGG.defaultBlockState()); -+ io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState, -+ new org.bukkit.craftbukkit.boss.CraftDragonBattle(this)); -+ // Paper end - Add DragonEggFormEvent -+ if (this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg || !this.previouslyKilled) { // Paper - Add toggle for always placing the dragon egg -+ // Paper start - Add DragonEggFormEvent -+ // this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), Blocks.DRAGON_EGG.defaultBlockState()); -+ } else { -+ eggEvent.setCancelled(true); -+ } -+ if (eggEvent.callEvent()) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) eggEvent.getNewState()).place(net.minecraft.world.level.block.Block.UPDATE_ALL); -+ // Paper end - Add DragonEggFormEvent - } - - this.previouslyKilled = true; -@@ -380,6 +_,24 @@ - this.gateways.clear(); - } - -+ // Paper start - More DragonBattle API -+ public boolean spawnNewGatewayIfPossible() { -+ if (!this.gateways.isEmpty()) { -+ this.spawnNewGateway(); -+ return true; -+ } -+ return false; -+ } -+ -+ public List getSpikeCrystals() { -+ final List endCrystals = new java.util.ArrayList<>(); -+ for (final SpikeFeature.EndSpike spike : SpikeFeature.getSpikesForLevel(this.level)) { -+ endCrystals.addAll(this.level.getEntitiesOfClass(EndCrystal.class, spike.getTopBoundingBox())); -+ } -+ return endCrystals; -+ } -+ // Paper end - More DragonBattle API -+ - private void spawnNewGateway() { - if (!this.gateways.isEmpty()) { - int i = this.gateways.remove(this.gateways.size() - 1); -@@ -410,6 +_,11 @@ - this.portalLocation = this.portalLocation.atY(Math.max(this.level.getMinY() + 1, this.portalLocation.getY())); - } - -+ // Paper start - Prevent "softlocked" exit portal generation -+ if (this.portalLocation.getY() <= this.level.getMinY()) { -+ this.portalLocation = this.portalLocation.atY(this.level.getMinY() + 1); -+ } -+ // Paper end - Prevent "softlocked" exit portal generation - if (endPodiumFeature.place( - FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation - )) { -@@ -428,6 +_,7 @@ - enderDragon.snapTo(this.origin.getX(), 128 + this.origin.getY(), this.origin.getZ(), this.level.random.nextFloat() * 360.0F, 0.0F); - this.level.addFreshEntity(enderDragon); - this.dragonUUID = enderDragon.getUUID(); -+ this.resetSpikeCrystals(); // Paper - Reset ender crystals on dragon spawn - } - - return enderDragon; -@@ -439,6 +_,10 @@ - this.ticksSinceDragonSeen = 0; - if (dragon.hasCustomName()) { - this.dragonEvent.setName(dragon.getDisplayName()); -+ // Paper start - ensure reset EnderDragon boss event name -+ } else { -+ this.dragonEvent.setName(DEFAULT_BOSS_EVENT_NAME); -+ // Paper end - ensure reset EnderDragon boss event name - } - } - } -@@ -466,7 +_,13 @@ - return this.previouslyKilled; - } - -- public void tryRespawn() { -+ public boolean tryRespawn() { // CraftBukkit - return boolean -+ // Paper start - Perf: Do crystal-portal proximity check before entity lookup -+ return this.tryRespawn(null); -+ } -+ -+ public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal -+ // Paper end - Perf: Do crystal-portal proximity check before entity lookup - if (this.dragonKilled && this.respawnStage == null) { - BlockPos blockPos = this.portalLocation; - if (blockPos == null) { -@@ -481,6 +_,22 @@ - - blockPos = this.portalLocation; - } -+ // Paper start - Perf: Do crystal-portal proximity check before entity lookup -+ if (placedEndCrystalPos != null && !level.paperConfig().misc.allowRemoteEnderDragonRespawning) { -+ // The end crystal must be 0 or 1 higher than the portal origin -+ int dy = placedEndCrystalPos.getY() - blockPos.getY(); -+ if (dy != 0 && dy != 1) { -+ return false; -+ } -+ // The end crystal must be within a distance of 1 in one planar direction, and 3 in the other -+ int dx = placedEndCrystalPos.getX() - blockPos.getX(); -+ int dz = placedEndCrystalPos.getZ() - blockPos.getZ(); -+ if (!((dx >= -1 && dx <= 1 && dz >= -3 && dz <= 3) || (dx >= -3 && dx <= 3 && dz >= -1 && dz <= 1))) { -+ return false; -+ } -+ } -+ // Paper end - Perf: Do crystal-portal proximity check before entity lookup -+ - - List list = Lists.newArrayList(); - BlockPos blockPos1 = blockPos.above(1); -@@ -488,18 +_,19 @@ - for (Direction direction : Direction.Plane.HORIZONTAL) { - List entitiesOfClass = this.level.getEntitiesOfClass(EndCrystal.class, new AABB(blockPos1.relative(direction, 2))); - if (entitiesOfClass.isEmpty()) { -- return; -+ return false; // CraftBukkit - return value - } - - list.addAll(entitiesOfClass); - } - - LOGGER.debug("Found all crystals, respawning dragon."); -- this.respawnDragon(list); -+ return this.respawnDragon(list); // CraftBukkit - return value - } -+ return false; // CraftBukkit - return value - } - -- public void respawnDragon(List crystals) { -+ public boolean respawnDragon(List crystals) { // CraftBukkit - return boolean - if (this.dragonKilled && this.respawnStage == null) { - for (BlockPattern.BlockPatternMatch blockPatternMatch = this.findExitPortal(); blockPatternMatch != null; blockPatternMatch = this.findExitPortal()) { - for (int i = 0; i < this.exitPortalPattern.getWidth(); i++) { -@@ -518,7 +_,9 @@ - this.respawnTime = 0; - this.spawnExitPortal(false); - this.respawnCrystals = crystals; -+ return true; // CraftBukkit - return value - } -+ return false; // CraftBukkit - return value - } - - public void resetSpikeCrystals() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EnderDragonFight.java.patch b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EnderDragonFight.java.patch new file mode 100644 index 000000000000..4ffccc81aa2b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/dimension/end/EnderDragonFight.java.patch @@ -0,0 +1,181 @@ +--- a/net/minecraft/world/level/dimension/end/EnderDragonFight.java ++++ b/net/minecraft/world/level/dimension/end/EnderDragonFight.java +@@ -155,6 +_,12 @@ + ); + this.dragonEvent.setPlayBossMusic(true).setCreateWorldFog(true); + this.validPlayer = EntitySelector.ENTITY_STILL_ALIVE.and(EntitySelector.withinDistance(origin.getX(), 128 + origin.getY(), origin.getZ(), 192.0)); ++ // Paper start - Add config to disable ender dragon legacy check ++ if (this.isDirty() && !level.paperConfig().entities.spawning.scanForLegacyEnderDragon) { ++ this.needsStateScanning = false; ++ this.dragonKilled = true; ++ } ++ // Paper end - Add config to disable ender dragon legacy check + if (this.gateways.isEmpty()) { + ObjectArrayList newGateways = new ObjectArrayList<>(ContiguousSet.create(Range.closedOpen(0, 20), DiscreteDomain.integers())); + Util.shuffle(newGateways, RandomSource.createThreadLocalInstance(seed)); +@@ -241,9 +_,9 @@ + this.dragonUUID = dragon.getUUID(); + LOGGER.info("Found that there's a dragon still alive ({})", dragon); + this.dragonKilled = false; +- if (!activePortalExists) { ++ if (!activePortalExists && this.level.paperConfig().entities.behavior.shouldRemoveDragon) { // Paper - Toggle for removing existing dragon + LOGGER.info("But we didn't have a portal, let's remove it."); +- dragon.discard(); ++ dragon.discard(null); // CraftBukkit - add Bukkit remove cause + this.dragonUUID = null; + } + } +@@ -404,13 +_,20 @@ + this.dragonEvent.setVisible(false); + this.spawnExitPortal(true); + this.spawnNewGateway(); +- if (!this.hasPreviouslyKilledDragon) { +- this.level +- .setBlockAndUpdate( +- this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)), +- Blocks.DRAGON_EGG.defaultBlockState() +- ); +- } ++ // Paper start - Add DragonEggFormEvent ++ BlockPos eggPosition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.origin)); ++ org.bukkit.craftbukkit.block.CraftBlockState eggState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.level, eggPosition); ++ eggState.setBlock(Blocks.DRAGON_EGG.defaultBlockState()); ++ io.papermc.paper.event.block.DragonEggFormEvent eggEvent = new io.papermc.paper.event.block.DragonEggFormEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(this.level, eggPosition), eggState, new org.bukkit.craftbukkit.boss.CraftDragonBattle(this) ++ ); ++ if (!this.level.paperConfig().entities.behavior.enderDragonsDeathAlwaysPlacesDragonEgg && this.hasPreviouslyKilledDragon) { // Paper - Add toggle for always placing the dragon egg ++ eggEvent.setCancelled(true); ++ } ++ if (eggEvent.callEvent()) { ++ ((org.bukkit.craftbukkit.block.CraftBlockState)eggEvent.getNewState()).place(net.minecraft.world.level.block.Block.UPDATE_ALL); ++ } ++ // Paper end - Add DragonEggFormEvent + + this.hasPreviouslyKilledDragon = true; + this.dragonKilled = true; +@@ -425,6 +_,24 @@ + this.setDirty(); + } + ++ // Paper start - More DragonBattle API ++ public boolean spawnNewGatewayIfPossible() { ++ if (!this.gateways.isEmpty()) { ++ this.spawnNewGateway(); ++ return true; ++ } ++ return false; ++ } ++ ++ public List getSpikeCrystals() { ++ final List endCrystals = new java.util.ArrayList<>(); ++ for (final EndSpikeFeature.EndSpike spike : EndSpikeFeature.getSpikesForLevel(this.level)) { ++ endCrystals.addAll(this.level.getEntitiesOfClass(EndCrystal.class, spike.getTopBoundingBox())); ++ } ++ return endCrystals; ++ } ++ // Paper end - More DragonBattle API ++ + private void spawnNewGateway() { + if (!this.gateways.isEmpty()) { + int gateway = this.gateways.remove(this.gateways.size() - 1); +@@ -456,6 +_,12 @@ + this.exitPortalLocation = this.exitPortalLocation.atY(Math.max(this.level.getMinY() + 1, this.exitPortalLocation.getY())); + this.setDirty(); + } ++ // Paper start - Prevent "softlocked" exit portal generation ++ else if (this.exitPortalLocation.getY() <= this.level.getMinY()) { ++ this.exitPortalLocation = this.exitPortalLocation.atY(this.level.getMinY() + 1); ++ this.setDirty(); ++ } ++ // Paper end - Prevent "softlocked" exit portal generation + + if (feature.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.exitPortalLocation)) { + int chunkRadius = Mth.positiveCeilDiv(4, 16); +@@ -473,6 +_,7 @@ + dragon.snapTo(this.origin.getX(), 128 + this.origin.getY(), this.origin.getZ(), this.level.getRandom().nextFloat() * 360.0F, 0.0F); + this.level.addFreshEntity(dragon); + this.dragonUUID = dragon.getUUID(); ++ this.resetSpikeCrystals(); // Paper - Reset ender crystals on dragon spawn + this.setDirty(); + } + +@@ -485,6 +_,10 @@ + this.ticksSinceDragonSeen = 0; + if (dragon.hasCustomName()) { + this.dragonEvent.setName(dragon.getDisplayName()); ++ // Paper start - ensure reset EnderDragon boss event name ++ } else { ++ this.dragonEvent.setName(EVENT_DISPLAY_NAME); ++ // Paper end - ensure reset EnderDragon boss event name + } + } + } +@@ -517,7 +_,13 @@ + return this.hasPreviouslyKilledDragon; + } + +- public void tryRespawn() { ++ public boolean tryRespawn() { // CraftBukkit - return boolean ++ // Paper start - Perf: Do crystal-portal proximity check before entity lookup ++ return this.tryRespawn(null); ++ } ++ ++ public boolean tryRespawn(@Nullable final BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal ++ // Paper end - Perf: Do crystal-portal proximity check before entity lookup + if (this.dragonKilled && this.respawnStage == null) { + BlockPos location = this.exitPortalLocation; + if (location == null) { +@@ -532,6 +_,20 @@ + + location = this.exitPortalLocation; + } ++ // Paper start - Perf: Do crystal-portal proximity check before entity lookup ++ if (placedEndCrystalPos != null && !this.level.paperConfig().misc.allowRemoteEnderDragonRespawning) { ++ int dy = placedEndCrystalPos.getY() - location.getY(); ++ if (dy != 0 && dy != 1) { ++ return false; ++ } ++ ++ int dx = placedEndCrystalPos.getX() - location.getX(); ++ int dz = placedEndCrystalPos.getZ() - location.getZ(); ++ if (!((dx >= -1 && dx <= 1 && dz >= -4 && dz <= 4) || (dx >= -4 && dx <= 4 && dz >= -1 && dz <= 1))) { ++ return false; ++ } ++ } ++ // Paper end - Perf: Do crystal-portal proximity check before entity lookup + + List crystals = Lists.newArrayList(); + BlockPos center = location.above(1); +@@ -539,18 +_,19 @@ + for (Direction direction : Direction.Plane.HORIZONTAL) { + List found = this.level.getEntitiesOfClass(EndCrystal.class, new AABB(center.relative(direction, 3))); + if (found.isEmpty()) { +- return; ++ return false; // CraftBukkit - return value + } + + crystals.addAll(found); + } + + LOGGER.debug("Found all crystals, respawning dragon."); +- this.respawnDragon(crystals); ++ return this.respawnDragon(crystals); // CraftBukkit - return value + } ++ return false; // CraftBukkit - return value + } + +- public void respawnDragon(final List crystals) { ++ public boolean respawnDragon(final List crystals) { // CraftBukkit - return boolean + if (this.dragonKilled && this.respawnStage == null) { + for (BlockPattern.BlockPatternMatch portal = this.findExitPortal(); portal != null; portal = this.findExitPortal()) { + for (int x = 0; x < this.exitPortalPattern.getWidth(); x++) { +@@ -570,7 +_,9 @@ + this.spawnExitPortal(false); + this.respawnCrystals = crystals.stream().map(EntityReference::of).toList(); + this.setDirty(); ++ return true; // CraftBukkit - return value + } ++ return false; // CraftBukkit - return value + } + + public void resetSpikeCrystals() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch index f5c795978fc0..d662e184a0ca 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch @@ -10,7 +10,7 @@ + this.setRemoved(removalReason, null); + } + -+ void setRemoved(Entity.RemovalReason removalReason, @javax.annotation.Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause eventCause); ++ void setRemoved(Entity.RemovalReason removalReason, org.bukkit.event.entity.EntityRemoveEvent.@org.jspecify.annotations.Nullable Cause eventCause); + // CraftBukkit end - add Bukkit remove cause boolean shouldBeSaved(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch index ba9179927ba5..aed26f44b809 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/entity/EntitySection.java +++ b/net/minecraft/world/level/entity/EntitySection.java @@ -19,6 +_,12 @@ - this.storage = new ClassInstanceMultiMap<>(entityClazz); + this.storage = new ClassInstanceMultiMap<>(entityClass); } + // Paper start - support retrieving all entities, regardless of whether they are accessible @@ -10,6 +10,6 @@ + } + // Paper end - support retrieving all entities, regardless of whether they are accessible + - public void add(T entity) { + public void add(final T entity) { this.storage.add(entity); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch index a6c808035bd3..4a9190ee09f0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/entity/EntitySectionStorage.java +++ b/net/minecraft/world/level/entity/EntitySectionStorage.java @@ -34,6 +_,16 @@ - this.intialSectionVisibility = initialSectionVisibility; + this.intialSectionVisibility = intialSectionVisibility; } + // Paper start - support retrieving all entities, regardless of whether they are accessible @@ -14,6 +14,6 @@ + } + // Paper end - support retrieving all entities, regardless of whether they are accessible + - public void forEachAccessibleNonEmptySection(AABB boundingBox, AbortableIterationConsumer> consumer) { - int sectionPosCoord = SectionPos.posToSectionCoord(boundingBox.minX - 2.0); - int sectionPosCoord1 = SectionPos.posToSectionCoord(boundingBox.minY - 4.0); + public void forEachAccessibleNonEmptySection(final AABB bb, final AbortableIterationConsumer> output) { + int xMin = SectionPos.posToSectionCoord(bb.minX - 2.0); + int yMin = SectionPos.posToSectionCoord(bb.minY - 4.0); diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch index a9e2d66b722a..11f5a46a69da 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch @@ -7,5 +7,5 @@ - private final EntitySectionStorage sectionStorage; + public final EntitySectionStorage sectionStorage; // Paper - public - public LevelEntityGetterAdapter(EntityLookup visibleEntities, EntitySectionStorage sectionStorage) { + public LevelEntityGetterAdapter(final EntityLookup visibleEntities, final EntitySectionStorage sectionStorage) { this.visibleEntities = visibleEntities; diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch index 62e3e6784e6c..1008a9bc4535 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -52,6 +_,16 @@ +@@ -53,6 +_,16 @@ this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage); } + // CraftBukkit start - add method to get all entities in chunk + public List getEntities(ChunkPos chunkPos) { -+ return this.sectionStorage.getExistingSectionsInChunk(chunkPos.toLong()).flatMap(EntitySection::getEntities).map(entity -> (Entity) entity).collect(Collectors.toList()); ++ return this.sectionStorage.getExistingSectionsInChunk(chunkPos.pack()).flatMap(EntitySection::getEntities).map(entity -> (Entity) entity).collect(Collectors.toList()); + } + + public boolean isPending(long pair) { @@ -14,27 +14,27 @@ + } + // CraftBukkit end + - void removeSectionIfEmpty(long sectionKey, EntitySection section) { + private void removeSectionIfEmpty(final long sectionPos, final EntitySection section) { if (section.isEmpty()) { - this.sectionStorage.remove(sectionKey); -@@ -59,6 +_,7 @@ + this.sectionStorage.remove(sectionPos); +@@ -60,6 +_,7 @@ } - private boolean addEntityUuid(T entity) { + private boolean addEntityUuid(final T entity) { + org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper if (!this.knownUuids.add(entity.getUUID())) { LOGGER.warn("UUID of added entity already exists: {}", entity); return false; -@@ -72,6 +_,17 @@ +@@ -73,6 +_,17 @@ } - private boolean addEntity(T entity, boolean worldGenSpawned) { + private boolean addEntity(final T entity, final boolean loaded) { + org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper + // Paper start - chunk system hooks + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; + boolean wasRemoved = entityCasted.isRemoved(); -+ boolean screened = ca.spottedleaf.moonrise.common.PlatformHooks.get().screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, worldGenSpawned, true); ++ boolean screened = ca.spottedleaf.moonrise.common.PlatformHooks.get().screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, loaded, true); + if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { + // removed by callback + return false; @@ -43,99 +43,99 @@ if (!this.addEntityUuid(entity)) { return false; } else { -@@ -113,19 +_,23 @@ +@@ -114,19 +_,23 @@ } - void startTicking(T entity) { + private void startTicking(final T entity) { + org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper this.callbacks.onTickingStart(entity); } - void stopTicking(T entity) { + private void stopTicking(final T entity) { + org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper this.callbacks.onTickingEnd(entity); } - void startTracking(T entity) { + private void startTracking(final T entity) { + org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper this.visibleEntityStorage.add(entity); this.callbacks.onTrackingStart(entity); } - void stopTracking(T entity) { + private void stopTracking(final T entity) { + org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper this.callbacks.onTrackingEnd(entity); this.visibleEntityStorage.remove(entity); } -@@ -136,6 +_,7 @@ +@@ -137,6 +_,7 @@ } - public void updateChunkStatus(ChunkPos pos, Visibility visibility) { + public void updateChunkStatus(final ChunkPos pos, final Visibility chunkStatus) { + org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper - long packedChunkPos = pos.toLong(); - if (visibility == Visibility.HIDDEN) { - this.chunkVisibility.remove(packedChunkPos); -@@ -169,6 +_,7 @@ + long chunkPosKey = pos.pack(); + if (chunkStatus == Visibility.HIDDEN) { + this.chunkVisibility.remove(chunkPosKey); +@@ -170,6 +_,7 @@ } - public void ensureChunkQueuedForLoad(long chunkPosValue) { + public void ensureChunkQueuedForLoad(final long chunkPos) { + org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper - PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue); + PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPos); if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { - this.requestChunkLoad(chunkPosValue); -@@ -176,6 +_,11 @@ + this.requestChunkLoad(chunkPos); +@@ -177,6 +_,11 @@ } - private boolean storeChunkSections(long chunkPosValue, Consumer entityAction) { + private boolean storeChunkSections(final long chunkPos, final Consumer savedEntityVisitor) { + // CraftBukkit start -+ return storeChunkSections(chunkPosValue, entityAction, false); ++ return storeChunkSections(chunkPos, savedEntityVisitor, false); + } -+ private boolean storeChunkSections(long chunkPosValue, Consumer entityAction, boolean callEvent) { ++ private boolean storeChunkSections(final long chunkPos, final Consumer savedEntityVisitor, final boolean callEvent) { + // CraftBukkit end - PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue); + PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPos); if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) { return false; -@@ -186,6 +_,7 @@ +@@ -187,6 +_,7 @@ .collect(Collectors.toList()); - if (list.isEmpty()) { + if (rootEntitiesToSave.isEmpty()) { if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) { -+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(chunkPosValue), ImmutableList.of()); // CraftBukkit - this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), ImmutableList.of())); ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), ImmutableList.of()); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), ImmutableList.of())); } -@@ -194,6 +_,7 @@ - this.requestChunkLoad(chunkPosValue); +@@ -195,6 +_,7 @@ + this.requestChunkLoad(chunkPos); return false; } else { -+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(chunkPosValue), list.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit - this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), list)); - list.forEach(entityAction); ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), rootEntitiesToSave.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), rootEntitiesToSave)); + rootEntitiesToSave.forEach(savedEntityVisitor); return true; -@@ -202,6 +_,7 @@ +@@ -203,6 +_,7 @@ } - private void requestChunkLoad(long chunkPosValue) { + private void requestChunkLoad(final long chunkKey) { + org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper - this.chunkLoadStatuses.put(chunkPosValue, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); - ChunkPos chunkPos = new ChunkPos(chunkPosValue); - this.permanentStorage.loadEntities(chunkPos).thenAccept(this.loadingInbox::add).exceptionally(throwable -> { -@@ -211,7 +_,8 @@ + this.chunkLoadStatuses.put(chunkKey, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); + ChunkPos pos = ChunkPos.unpack(chunkKey); + this.permanentStorage.loadEntities(pos).thenAccept(this.loadingInbox::add).exceptionally(t -> { +@@ -212,7 +_,8 @@ } - private boolean processChunkUnload(long chunkPosValue) { -- boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity)); + private boolean processChunkUnload(final long chunkKey) { +- boolean storeSuccessful = this.storeChunkSections(chunkKey, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity)); + org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper -+ boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity), true); // CraftBukkit - add boolean for event call - if (!flag) { ++ boolean storeSuccessful = this.storeChunkSections(chunkKey, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity), true); // CraftBukkit - add boolean for event call + if (!storeSuccessful) { return false; } else { -@@ -221,7 +_,7 @@ +@@ -222,7 +_,7 @@ } - private void unloadEntity(EntityAccess entity) { -- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); -+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); // CraftBukkit - add Bukkit remove cause - entity.setLevelCallback(EntityInLevelCallback.NULL); + private void unloadEntity(final EntityAccess e) { +- e.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); ++ e.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); // CraftBukkit - add Bukkit remove cause + e.setLevelCallback(EntityInLevelCallback.NULL); } @@ -231,14 +_,20 @@ @@ -143,13 +143,13 @@ public void processPendingLoads() { + org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper - ChunkEntities chunkEntities; - while ((chunkEntities = this.loadingInbox.poll()) != null) { - chunkEntities.getEntities().forEach(entity -> this.addEntity((T)entity, true)); - this.chunkLoadStatuses.put(chunkEntities.getPos().toLong(), PersistentEntitySectionManager.ChunkLoadStatus.LOADED); + ChunkEntities loadedChunk; + while ((loadedChunk = this.loadingInbox.poll()) != null) { + loadedChunk.getEntities().forEach(e -> this.addEntity((T)e, true)); + this.chunkLoadStatuses.put(loadedChunk.getPos().pack(), PersistentEntitySectionManager.ChunkLoadStatus.LOADED); + // CraftBukkit start - call entity load event -+ List entities = this.getEntities(chunkEntities.getPos()); -+ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, chunkEntities.getPos(), entities); ++ List entities = this.getEntities(loadedChunk.getPos()); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, loadedChunk.getPos(), entities); + // CraftBukkit end } } @@ -164,17 +164,17 @@ public void autoSave() { + org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper - this.getAllChunksToSave().forEach(packedChunkPos -> { - boolean flag = this.chunkVisibility.get(packedChunkPos) == Visibility.HIDDEN; - if (flag) { + this.getAllChunksToSave().forEach(chunkKey -> { + boolean shouldUnload = this.chunkVisibility.get(chunkKey) == Visibility.HIDDEN; + if (shouldUnload) { @@ -267,6 +_,7 @@ } public void saveAll() { + org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper - LongSet allChunksToSave = this.getAllChunksToSave(); + LongSet chunksToSave = this.getAllChunksToSave(); - while (!allChunksToSave.isEmpty()) { + while (!chunksToSave.isEmpty()) { @@ -283,7 +_,13 @@ @Override @@ -190,18 +190,18 @@ this.permanentStorage.close(); } -@@ -384,6 +_,7 @@ - BlockPos blockPos = this.entity.blockPosition(); - long packedSectionPos = SectionPos.asLong(blockPos); - if (packedSectionPos != this.currentSectionKey) { +@@ -386,6 +_,7 @@ + BlockPos pos = this.entity.blockPosition(); + long newSectionPos = SectionPos.asLong(pos); + if (newSectionPos != this.currentSectionKey) { + org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper - Visibility status = this.currentSection.getStatus(); + Visibility previousStatus = this.currentSection.getStatus(); if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER -@@ -431,6 +_,7 @@ +@@ -433,6 +_,7 @@ @Override - public void onRemove(Entity.RemovalReason reason) { + public void onRemove(final Entity.RemovalReason reason) { + org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER diff --git a/paper-server/patches/sources/net/minecraft/world/level/gameevent/DynamicGameEventListener.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gameevent/DynamicGameEventListener.java.patch index a920d35331d0..5cec11d673fa 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gameevent/DynamicGameEventListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gameevent/DynamicGameEventListener.java.patch @@ -2,10 +2,10 @@ +++ b/net/minecraft/world/level/gameevent/DynamicGameEventListener.java @@ -40,7 +_,7 @@ - private static void ifChunkExists(LevelReader level, @Nullable SectionPos sectionPos, Consumer dispatcherConsumer) { + private static void ifChunkExists(final LevelReader level, final @Nullable SectionPos sectionPos, final Consumer action) { if (sectionPos != null) { - ChunkAccess chunk = level.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.FULL, false); + ChunkAccess chunk = level.getChunkIfLoadedImmediately(sectionPos.getX(), sectionPos.getZ()); // Paper - Perf: can cause sync loads while completing a chunk, resulting in deadlock if (chunk != null) { - dispatcherConsumer.accept(chunk.getListenerRegistry(sectionPos.y())); + action.accept(chunk.getListenerRegistry(sectionPos.y())); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEvent.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEvent.java.patch index efcac86d58ce..95139c54f334 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEvent.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEvent.java.patch @@ -3,7 +3,7 @@ @@ -85,7 +_,7 @@ } - private static Holder.Reference register(String name, int notificationRadius) { + private static Holder.Reference register(final String name, final int notificationRadius) { - return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, Identifier.withDefaultNamespace(name), new GameEvent(notificationRadius)); + return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, Identifier.withDefaultNamespace(name), new GameEvent(notificationRadius)); // Paper - run with listeners } diff --git a/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEventDispatcher.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEventDispatcher.java.patch index 043949fc6716..56b704270597 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEventDispatcher.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gameevent/GameEventDispatcher.java.patch @@ -1,27 +1,27 @@ --- a/net/minecraft/world/level/gameevent/GameEventDispatcher.java +++ b/net/minecraft/world/level/gameevent/GameEventDispatcher.java @@ -22,6 +_,15 @@ - public void post(Holder gameEvent, Vec3 pos, GameEvent.Context context) { - int notificationRadius = gameEvent.value().notificationRadius(); - BlockPos blockPos = BlockPos.containing(pos); + public void post(final Holder gameEvent, final Vec3 position, final GameEvent.Context context) { + int radius = gameEvent.value().notificationRadius(); + BlockPos center = BlockPos.containing(position); + // CraftBukkit start + org.bukkit.event.world.GenericGameEvent apiEvent = new org.bukkit.event.world.GenericGameEvent( -+ org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(gameEvent), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, this.level), -+ (context.sourceEntity() == null) ? null : context.sourceEntity().getBukkitEntity(), notificationRadius, !org.bukkit.Bukkit.isPrimaryThread()); ++ org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(gameEvent), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(center, this.level), ++ (context.sourceEntity() == null) ? null : context.sourceEntity().getBukkitEntity(), radius, !org.bukkit.Bukkit.isPrimaryThread()); + if (!apiEvent.callEvent()) { + return; + } -+ notificationRadius = apiEvent.getRadius(); ++ radius = apiEvent.getRadius(); + // CraftBukkit end - int sectionPosCoord = SectionPos.blockToSectionCoord(blockPos.getX() - notificationRadius); - int sectionPosCoord1 = SectionPos.blockToSectionCoord(blockPos.getY() - notificationRadius); - int sectionPosCoord2 = SectionPos.blockToSectionCoord(blockPos.getZ() - notificationRadius); + int sectionMinX = SectionPos.blockToSectionCoord(center.getX() - radius); + int sectionMinY = SectionPos.blockToSectionCoord(center.getY() - radius); + int sectionMinZ = SectionPos.blockToSectionCoord(center.getZ() - radius); @@ -40,7 +_,7 @@ - for (int i = sectionPosCoord; i <= sectionPosCoord3; i++) { - for (int i1 = sectionPosCoord2; i1 <= sectionPosCoord5; i1++) { -- ChunkAccess chunkNow = this.level.getChunkSource().getChunkNow(i, i1); -+ ChunkAccess chunkNow = this.level.getChunkIfLoadedImmediately(i, i1); // Paper - Use getChunkIfLoadedImmediately - if (chunkNow != null) { - for (int i2 = sectionPosCoord1; i2 <= sectionPosCoord4; i2++) { - flag |= chunkNow.getListenerRegistry(i2).visitInRangeListeners(gameEvent, pos, context, listenerVisitor); + for (int chunkX = sectionMinX; chunkX <= sectionMaxX; chunkX++) { + for (int chunkZ = sectionMinZ; chunkZ <= sectionMaxZ; chunkZ++) { +- ChunkAccess chunk = this.level.getChunkSource().getChunkNow(chunkX, chunkZ); ++ ChunkAccess chunk = this.level.getChunkIfLoadedImmediately(chunkX, chunkZ); // Paper - Use getChunkIfLoadedImmediately + if (chunk != null) { + for (int section = sectionMinY; section <= sectionMaxY; section++) { + applicable |= chunk.getListenerRegistry(section).visitInRangeListeners(gameEvent, position, context, visitListeners); diff --git a/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch index c56f5cbcf66d..e102937119a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch @@ -1,27 +1,27 @@ --- a/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java +++ b/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java @@ -123,7 +_,7 @@ - public static Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( - VibrationInfo.CODEC.lenientOptionalFieldOf("event").forGetter(data -> Optional.ofNullable(data.currentVibration)), + public static final Codec CODEC = RecordCodecBuilder.create( + i -> i.group( + VibrationInfo.CODEC.lenientOptionalFieldOf("event").forGetter(o -> Optional.ofNullable(o.currentVibration)), - VibrationSelector.CODEC.fieldOf("selector").forGetter(VibrationSystem.Data::getSelectionStrategy), + VibrationSelector.CODEC.optionalFieldOf("selector").xmap(o -> o.orElseGet(VibrationSelector::new), Optional::of).forGetter(VibrationSystem.Data::getSelectionStrategy), // Paper - fix MapLike spam for missing "selector" in 1.19.2 ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks) ) .apply( -@@ -212,7 +_,14 @@ +@@ -219,7 +_,14 @@ return false; } else { - Vec3 vec3 = position.get(); -- if (!vibrationUser.canReceiveVibration(level, BlockPos.containing(pos), gameEvent, context)) { + Vec3 destination = listenerSourcePos.get(); +- if (!user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context)) { + // CraftBukkit start -+ boolean defaultCancel = !vibrationUser.canReceiveVibration(level, BlockPos.containing(pos), gameEvent, context); ++ boolean defaultCancel = !user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context); + Entity entity = context.sourceEntity(); -+ org.bukkit.event.block.BlockReceiveGameEvent event1 = new org.bukkit.event.block.BlockReceiveGameEvent(org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(gameEvent), org.bukkit.craftbukkit.block.CraftBlock.at(level, BlockPos.containing(vec3)), (entity == null) ? null : entity.getBukkitEntity()); ++ org.bukkit.event.block.BlockReceiveGameEvent event1 = new org.bukkit.event.block.BlockReceiveGameEvent(org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(event), org.bukkit.craftbukkit.block.CraftBlock.at(level, BlockPos.containing(sourcePosition)), (entity == null) ? null : entity.getBukkitEntity()); + event1.setCancelled(defaultCancel); + level.getCraftServer().getPluginManager().callEvent(event1); + if (event1.isCancelled()) { + // CraftBukkit end return false; - } else if (isOccluded(level, pos, vec3)) { + } else if (isOccluded(level, sourcePosition, destination)) { return false; diff --git a/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRuleMap.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRuleMap.java.patch index cee18bdd0ce5..e33be7abc8ba 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRuleMap.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRuleMap.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/gamerules/GameRuleMap.java +++ b/net/minecraft/world/level/gamerules/GameRuleMap.java -@@ -15,9 +_,16 @@ - public static final Codec CODEC = Codec., Object>dispatchedMap(BuiltInRegistries.GAME_RULE.byNameCodec(), GameRule::valueCodec) - .xmap(GameRuleMap::ofTrusted, GameRuleMap::map); +@@ -22,9 +_,16 @@ + Identifier.withDefaultNamespace("game_rules"), GameRuleMap::of, CODEC, DataFixTypes.SAVED_DATA_GAME_RULES + ); private final Reference2ObjectMap, Object> map; + private final @Nullable Object[] idAccess; // Paper - array backed gamerule access - array storage - GameRuleMap(Reference2ObjectMap, Object> map) { + private GameRuleMap(final Reference2ObjectMap, Object> map) { this.map = map; + // Paper start - array backed gamerule access - array storage + idAccess = new Object[GameRule.LAST_GAMERULE_INDEX]; @@ -16,27 +16,32 @@ + // Paper end - array backed gamerule access - array storage } - private static GameRuleMap ofTrusted(Map, Object> rules) { -@@ -39,18 +_,20 @@ + private static GameRuleMap ofTrusted(final Map, Object> map) { +@@ -46,16 +_,17 @@ } - public boolean has(GameRule rule) { -- return this.map.containsKey(rule); -+ return this.idAccess[rule.gameRuleIndex] != null; // Paper - array backed gamerule access - the gamerule map does not allow null values, so this suffices for a contains check (see net.minecraft.world.level.gamerules.GameRuleMap.setGameRule's non-null checks) + public boolean has(final GameRule gameRule) { +- return this.map.containsKey(gameRule); ++ return this.idAccess[gameRule.gameRuleIndex] != null; // Paper - array backed gamerule access - the gamerule map does not allow null values, so this suffices for a contains check (see net.minecraft.world.level.gamerules.GameRuleMap.setGameRule's non-null checks) } - public @Nullable T get(GameRule rule) { -- return (T)this.map.get(rule); -+ return (T) this.idAccess[rule.gameRuleIndex]; // Paper - array backed gamerule access + public @Nullable T get(final GameRule gameRule) { +- return (T)this.map.get(gameRule); ++ return (T)this.idAccess[gameRule.gameRuleIndex]; // Paper - array backed gamerule access } - public void set(GameRule rule, T value) { - this.map.put(rule, value); -+ this.idAccess[rule.gameRuleIndex] = value; // Paper - array backed gamerule access - above map is kept in sync instead of fully removing the map, which needs more diff. + public void set(final GameRule gameRule, final T value) { + this.setDirty(); + this.map.put(gameRule, value); ++ this.idAccess[gameRule.gameRuleIndex] = value; // Paper - array backed gamerule access - above map is kept in sync instead of fully removing the map, which needs more diff. } - public @Nullable T remove(GameRule rule) { -+ this.idAccess[rule.gameRuleIndex] = null; // Paper - array backed gamerule access - return (T)this.map.remove(rule); + public void reset(final GameRule gameRule) { +@@ -64,6 +_,7 @@ + + public @Nullable T remove(final GameRule gameRule) { + this.setDirty(); ++ this.idAccess[gameRule.gameRuleIndex] = null; // Paper - array backed gamerule access + return (T)this.map.remove(gameRule); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRules.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRules.java.patch index afb8178f0114..5c080676454e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRules.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gamerules/GameRules.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/gamerules/GameRules.java +++ b/net/minecraft/world/level/gamerules/GameRules.java -@@ -17,6 +_,14 @@ - import org.jspecify.annotations.Nullable; +@@ -21,6 +_,13 @@ public class GameRules { + private static final Logger LOGGER = LogUtils.getLogger(); + // Paper start - allow disabling gamerule limits + private static final boolean DISABLE_LIMITS = Boolean.getBoolean("paper.disableGameRuleLimits"); + @@ -11,59 +11,58 @@ + return DISABLE_LIMITS ? unlimited : limit; + } + // Paper end - allow disabling gamerule limits -+ public static final GameRule ADVANCE_TIME = registerBoolean("advance_time", GameRuleCategory.UPDATES, !SharedConstants.DEBUG_WORLD_RECREATE); public static final GameRule ADVANCE_WEATHER = registerBoolean("advance_weather", GameRuleCategory.UPDATES, !SharedConstants.DEBUG_WORLD_RECREATE); public static final GameRule ALLOW_ENTERING_NETHER_USING_PORTALS = registerBoolean( -@@ -114,13 +_,15 @@ +@@ -130,13 +_,15 @@ } } -- public void set(GameRule rule, T value, @Nullable MinecraftServer server) { -+ public void set(GameRule rule, T value, net.minecraft.server.level.@Nullable ServerLevel level) { // Paper - per-world game rules - if (!this.rules.has(rule)) { - throw new IllegalArgumentException("Tried to set invalid game rule"); +- public void set(final GameRule gameRule, final T value, final @Nullable MinecraftServer server) { ++ public void set(final GameRule gameRule, final T value, final net.minecraft.server.level.@Nullable ServerLevel level) { // Paper - per-world game rules + if (!this.rules.has(gameRule)) { + LOGGER.warn("Tried to set invalid game rule '{}' to value '{}'", gameRule.getIdentifierWithFallback(), value); } else { - this.rules.set(rule, value); + this.rules.set(gameRule, value); - if (server != null) { -- server.onGameRuleChanged(rule, value); +- server.onGameRuleChanged(gameRule, value); + // Paper start - per-world game rules + if (level != null) { -+ level.getServer().onGameRuleChanged(level, rule, value); ++ level.getServer().onGameRuleChanged(level, gameRule, value); + // Paper end - per-world game rules } } } -@@ -129,16 +_,22 @@ - return new GameRules(enabledFeatures, this.rules); +@@ -145,16 +_,22 @@ + return new GameRules(enabledFeatures, GameRuleMap.copyOf(this.rules)); } -- public void setAll(GameRules gameRules, @Nullable MinecraftServer server) { -- this.setAll(gameRules.rules, server); +- public void setAll(final GameRules other, final @Nullable MinecraftServer server) { +- this.setAll(other.rules, server); - } - -- public void setAll(GameRuleMap rules, @Nullable MinecraftServer server) { -- rules.keySet().forEach(rule -> this.setFromOther(rules, (GameRule)rule, server)); +- public void setAll(final GameRuleMap gameRulesMap, final @Nullable MinecraftServer server) { +- gameRulesMap.keySet().forEach(gameRule -> this.setFromOther(gameRulesMap, (GameRule)gameRule, server)); - } - -- private void setFromOther(GameRuleMap rules, GameRule rule, @Nullable MinecraftServer server) { -- this.set(rule, Objects.requireNonNull(rules.get(rule)), server); +- private void setFromOther(final GameRuleMap gameRulesMap, final GameRule gameRule, final @Nullable MinecraftServer server) { +- this.set(gameRule, Objects.requireNonNull(gameRulesMap.get(gameRule)), server); + // Paper start - per-world game rules -+ public void setAll(GameRules gameRules, net.minecraft.server.level.@Nullable ServerLevel level) { -+ this.setAll(gameRules.rules, level); ++ public void setAll(final GameRules other, final net.minecraft.server.level.@Nullable ServerLevel level) { ++ this.setAll(other.rules, level); + // Paper end - per-world game rules + } + + // Paper start - per-world game rules -+ public void setAll(GameRuleMap rules, net.minecraft.server.level.@Nullable ServerLevel level) { -+ rules.keySet().forEach(rule -> this.setFromOther(rules, (GameRule)rule, level)); ++ public void setAll(final GameRuleMap gameRulesMap, final net.minecraft.server.level.@Nullable ServerLevel level) { ++ gameRulesMap.keySet().forEach(gameRule -> this.setFromOther(gameRulesMap, (GameRule)gameRule, level)); + // Paper end - per-world game rules + } + + // Paper start - per-world game rules -+ private void setFromOther(GameRuleMap rules, GameRule rule, net.minecraft.server.level.@Nullable ServerLevel level) { -+ this.set(rule, Objects.requireNonNull(rules.get(rule)), level); ++ private void setFromOther(final GameRuleMap gameRulesMap, final GameRule gameRule, final net.minecraft.server.level.@Nullable ServerLevel level) { ++ this.set(gameRule, Objects.requireNonNull(gameRulesMap.get(gameRule)), level); + // Paper end - per-world game rules } - public void visitGameRuleTypes(GameRuleTypeVisitor visitor) { + public void visitGameRuleTypes(final GameRuleTypeVisitor visitor) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/DensityFunctions.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/DensityFunctions.java.patch index 95a6587fba98..8b232d52fd08 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/DensityFunctions.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/DensityFunctions.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/levelgen/DensityFunctions.java +++ b/net/minecraft/world/level/levelgen/DensityFunctions.java -@@ -512,6 +_,16 @@ +@@ -532,6 +_,16 @@ ); private static final float ISLAND_THRESHOLD = -0.9F; private final SimplexNoise islandNoise; @@ -15,41 +15,39 @@ + private static final ThreadLocal> noiseCache = ThreadLocal.withInitial(java.util.WeakHashMap::new); + // Paper end - Perf: Optimize end generation - public EndIslandDensityFunction(long seed) { - RandomSource randomSource = new LegacyRandomSource(seed); -@@ -524,15 +_,31 @@ - int i1 = z / 2; - int i2 = x % 2; - int i3 = z % 2; -- float f = 100.0F - Mth.sqrt(x * x + z * z) * 8.0F; -+ float f = 100.0F - (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixFarEndTerrainGeneration ? Mth.sqrt((long)x * (long)x + (long)z * (long)z) : Mth.sqrt(x * x + z * z)) * 8.0F; // Paper - cast ints to long when MC-159283 fix enabled - f = Mth.clamp(f, -100.0F, 80.0F); + public EndIslandDensityFunction(final long seed) { + RandomSource islandRandom = new LegacyRandomSource(seed); +@@ -544,15 +_,31 @@ + int chunkZ = sectionZ / 2; + int subSectionX = sectionX % 2; + int subSectionZ = sectionZ % 2; +- float doffs = 100.0F - Mth.sqrt(sectionX * sectionX + sectionZ * sectionZ) * 8.0F; ++ float doffs = 100.0F - (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixFarEndTerrainGeneration ? Mth.sqrt((long) sectionX * (long) sectionX + (long) sectionZ * (long) sectionZ) : Mth.sqrt(sectionX * sectionX + sectionZ * sectionZ)) * 8.0F; // Paper - cast ints to long when MC-159283 fix enabled + doffs = Mth.clamp(doffs, -100.0F, 80.0F); -+ NoiseCache cache = noiseCache.get().computeIfAbsent(noise, noiseKey -> new NoiseCache()); // Paper - Perf: Optimize end generation - for (int i4 = -12; i4 <= 12; i4++) { - for (int i5 = -12; i5 <= 12; i5++) { -- long l = i + i4; -- long l1 = i1 + i5; -+ long l = i + i4; final int chunkX = (int) l; // Paper - OBFHELPER -+ long l1 = i1 + i5; final int chunkZ = (int) l1; // Paper - OBFHELPER ++ NoiseCache cache = noiseCache.get().computeIfAbsent(islandNoise, noiseKey -> new NoiseCache()); // Paper - Perf: Optimize end generation + for (int xo = -12; xo <= 12; xo++) { + for (int zo = -12; zo <= 12; zo++) { + long totalChunkX = chunkX + xo; + long totalChunkZ = chunkZ + zo; + // Paper start - Perf: Optimize end generation by using a noise cache -+ final long chunkKey = net.minecraft.world.level.ChunkPos.asLong(chunkX, chunkZ); ++ final long chunkKey = net.minecraft.world.level.ChunkPos.pack((int) totalChunkX, (int) totalChunkZ); + final int cacheIndex = (int) it.unimi.dsi.fastutil.HashCommon.mix(chunkKey) & 8191; -+ float f1 = Float.MIN_VALUE; // noise value ++ float islandSize = Float.MIN_VALUE; // noise value + if (cache.keys[cacheIndex] == chunkKey) { + // Use cache -+ f1 = cache.values[cacheIndex]; ++ islandSize = cache.values[cacheIndex]; + } else { -+ // Vanilla function - if (l * l + l1 * l1 > 4096L && noise.getValue(l, l1) < -0.9F) { -- float f1 = (Mth.abs((float)l) * 3439.0F + Mth.abs((float)l1) * 147.0F) % 13.0F + 9.0F; -+ f1 = (Mth.abs((float)l) * 3439.0F + Mth.abs((float)l1) * 147.0F) % 13.0F + 9.0F; -+ } ++ // Vanilla function + if (totalChunkX * totalChunkX + totalChunkZ * totalChunkZ > 4096L && islandNoise.getValue(totalChunkX, totalChunkZ) < -0.9F) { +- float islandSize = (Mth.abs((float)totalChunkX) * 3439.0F + Mth.abs((float)totalChunkZ) * 147.0F) % 13.0F + 9.0F; ++ islandSize = (Mth.abs((float)totalChunkX) * 3439.0F + Mth.abs((float) totalChunkZ) * 147.0F) % 13.0F + 9.0F; ++ } + cache.keys[cacheIndex] = chunkKey; -+ cache.values[cacheIndex] = f1; ++ cache.values[cacheIndex] = islandSize; + } -+ if (f1 != Float.MIN_VALUE) { ++ if (islandSize != Float.MIN_VALUE) { + // Paper end - Perf: Optimize end generation - float f2 = i2 - i4 * 2; - float f3 = i3 - i5 * 2; - float f4 = 100.0F - Mth.sqrt(f2 * f2 + f3 * f3) * f1; + float xd = subSectionX - xo * 2; + float zd = subSectionZ - zo * 2; + float newDoffs = 100.0F - Mth.sqrt(xd * xd + zd * zd) * islandSize; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/FlatLevelSource.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/FlatLevelSource.java.patch index f1cd4a895b1e..53fb63d80f04 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/FlatLevelSource.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/FlatLevelSource.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/level/levelgen/FlatLevelSource.java +++ b/net/minecraft/world/level/levelgen/FlatLevelSource.java -@@ -33,17 +_,22 @@ +@@ -32,17 +_,22 @@ private final FlatLevelGeneratorSettings settings; - public FlatLevelSource(FlatLevelGeneratorSettings settings) { -- super(new FixedBiomeSource(settings.getBiome()), Util.memoize(settings::adjustGenerationSettings)); + public FlatLevelSource(final FlatLevelGeneratorSettings generatorSettings) { +- super(new FixedBiomeSource(generatorSettings.getBiome()), Util.memoize(generatorSettings::adjustGenerationSettings)); + // CraftBukkit start -+ this(settings, new FixedBiomeSource(settings.getBiome())); ++ this(generatorSettings, new FixedBiomeSource(generatorSettings.getBiome())); + } -+ public FlatLevelSource(FlatLevelGeneratorSettings settings, net.minecraft.world.level.biome.BiomeSource biomeSource) { -+ super(biomeSource, Util.memoize(settings::adjustGenerationSettings)); ++ public FlatLevelSource(final FlatLevelGeneratorSettings generatorSettings, final net.minecraft.world.level.biome.BiomeSource biomeSource) { ++ super(biomeSource, Util.memoize(generatorSettings::adjustGenerationSettings)); + // CraftBukkit end - this.settings = settings; + this.settings = generatorSettings; } @Override -- public ChunkGeneratorStructureState createState(HolderLookup structureSetLookup, RandomState randomState, long seed) { -+ public ChunkGeneratorStructureState createState(HolderLookup structureSetLookup, RandomState randomState, long seed, org.spigotmc.SpigotWorldConfig conf) { // Spigot - Stream> stream = this.settings +- public ChunkGeneratorStructureState createState(final HolderLookup structureSets, final RandomState randomState, final long levelSeed) { ++ public ChunkGeneratorStructureState createState(final HolderLookup structureSets, final RandomState randomState, final long levelSeed, final org.spigotmc.SpigotWorldConfig conf) { // Spigot + Stream> structures = this.settings .structureOverrides() .map(HolderSet::stream) - .orElseGet(() -> structureSetLookup.listElements().map(reference -> (Holder)reference)); -- return ChunkGeneratorStructureState.createForFlat(randomState, seed, this.biomeSource, stream); -+ return ChunkGeneratorStructureState.createForFlat(randomState, seed, this.biomeSource, stream, conf); // Spigot + .orElseGet(() -> structureSets.listElements().map(e -> (Holder)e)); +- return ChunkGeneratorStructureState.createForFlat(randomState, levelSeed, this.biomeSource, structures); ++ return ChunkGeneratorStructureState.createForFlat(randomState, levelSeed, this.biomeSource, structures, conf); // Spigot } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java.patch index 0b411864f6da..dfd1c2e4d7be 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -@@ -226,7 +_,7 @@ +@@ -266,7 +_,7 @@ @Override - public void buildSurface(WorldGenRegion region, StructureManager structureManager, RandomState random, ChunkAccess chunk) { - if (!SharedConstants.debugVoidTerrain(chunk.getPos()) && !SharedConstants.DEBUG_DISABLE_SURFACE) { -- WorldGenerationContext worldGenerationContext = new WorldGenerationContext(this, region); -+ WorldGenerationContext worldGenerationContext = new WorldGenerationContext(this, region, region.getMinecraftWorld()); // Paper - Flat bedrock generator settings + public void buildSurface(final WorldGenRegion region, final StructureManager structureManager, final RandomState randomState, final ChunkAccess protoChunk) { + if (!SharedConstants.debugVoidTerrain(protoChunk.getPos()) && !SharedConstants.DEBUG_DISABLE_SURFACE) { +- WorldGenerationContext context = new WorldGenerationContext(this, region); ++ WorldGenerationContext context = new WorldGenerationContext(this, region, region.getMinecraftWorld()); // Paper - Flat bedrock generator settings this.buildSurface( - chunk, - worldGenerationContext, -@@ -269,7 +_,7 @@ - NoiseChunk noiseChunk = chunk.getOrCreateNoiseChunk(chunkAccess -> this.createNoiseChunk(chunkAccess, structureManager, Blender.of(region), random)); + protoChunk, + context, +@@ -314,7 +_,7 @@ + NoiseChunk noiseChunk = chunk.getOrCreateNoiseChunk(c -> this.createNoiseChunk(c, structureManager, Blender.of(region), randomState)); Aquifer aquifer = noiseChunk.aquifer(); - CarvingContext carvingContext = new CarvingContext( -- this, region.registryAccess(), chunk.getHeightAccessorForGeneration(), noiseChunk, random, this.settings.value().surfaceRule() -+ this, region.registryAccess(), chunk.getHeightAccessorForGeneration(), noiseChunk, random, this.settings.value().surfaceRule(), region.getMinecraftWorld() // Paper - Flat bedrock generator settings + CarvingContext context = new CarvingContext( +- this, region.registryAccess(), chunk.getHeightAccessorForGeneration(), noiseChunk, randomState, this.settings.value().surfaceRule() ++ this, region.registryAccess(), chunk.getHeightAccessorForGeneration(), noiseChunk, randomState, this.settings.value().surfaceRule(), region.getMinecraftWorld() // Paper - Flat bedrock generator settings ); - CarvingMask carvingMask = ((ProtoChunk)chunk).getOrCreateCarvingMask(); + CarvingMask mask = ((ProtoChunk)chunk).getOrCreateCarvingMask(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch index 76603adde963..5bbe28c783cf 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch @@ -1,27 +1,27 @@ --- a/net/minecraft/world/level/levelgen/PatrolSpawner.java +++ b/net/minecraft/world/level/levelgen/PatrolSpawner.java -@@ -18,17 +_,47 @@ +@@ -18,17 +_,51 @@ @Override - public void tick(ServerLevel level, boolean spawnEnemies) { + public void tick(final ServerLevel level, final boolean spawnEnemies) { + if (level.paperConfig().entities.behavior.pillagerPatrols.disable || level.paperConfig().entities.behavior.pillagerPatrols.spawnChance == 0) return; // Paper - Add option to disable pillager patrols & Pillager patrol spawn settings and per player options if (spawnEnemies) { if (level.getGameRules().get(GameRules.SPAWN_PATROLS)) { - RandomSource randomSource = level.random; + RandomSource random = level.getRandom(); - this.nextTick--; - if (this.nextTick <= 0) { -- this.nextTick = this.nextTick + 12000 + randomSource.nextInt(1200); +- this.nextTick = this.nextTick + 12000 + random.nextInt(1200); - if (level.isBrightOutside()) { -- if (randomSource.nextInt(5) == 0) { -- int size = level.players().size(); +- if (random.nextInt(5) == 0) { +- int playerCount = level.players().size(); + // this.nextTick--; + // Paper start - Pillager patrol spawn settings and per player options -+ int size = level.players().size(); -+ if (size < 1) { ++ int playerCount = level.players().size(); ++ if (playerCount < 1) { + return; + } + -+ net.minecraft.server.level.ServerPlayer player = level.players().get(randomSource.nextInt(size)); ++ net.minecraft.server.level.ServerPlayer player = level.players().get(random.nextInt(playerCount)); + if (player.isSpectator()) { + return; + } @@ -37,30 +37,34 @@ + if (patrolSpawnDelay <= 0) { + long dayCount; + if (level.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) { -+ dayCount = player.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_TIME is counting in ticks ++ dayCount = player.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / net.minecraft.SharedConstants.TICKS_PER_GAME_DAY; // PLAY_TIME is counting in ticks + } else { -+ dayCount = level.getDayCount(); ++ dayCount = level ++ .registryAccess() ++ .get(net.minecraft.world.timeline.Timelines.OVERWORLD_DAY) ++ .map(timeline -> timeline.value().getPeriodCount(level.clockManager())) ++ .orElse(0); + } + if (level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { -+ player.patrolSpawnDelay += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomSource.nextInt(1200); ++ player.patrolSpawnDelay += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + random.nextInt(1200); + } else { -+ this.nextTick += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomSource.nextInt(1200); ++ this.nextTick += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + random.nextInt(1200); + } + + if (dayCount >= level.paperConfig().entities.behavior.pillagerPatrols.start.day && level.isBrightOutside()) { -+ if (randomSource.nextDouble() < level.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { ++ if (random.nextDouble() < level.paperConfig().entities.behavior.pillagerPatrols.spawnChance) { + // Paper end - Pillager patrol spawn settings and per player options - if (size >= 1) { -- Player player = level.players().get(randomSource.nextInt(size)); + if (playerCount >= 1) { +- Player player = level.players().get(random.nextInt(playerCount)); if (!player.isSpectator()) { if (!level.isCloseToVillage(player.blockPosition(), 2)) { - int i = (24 + randomSource.nextInt(24)) * (randomSource.nextBoolean() ? -1 : 1); -@@ -84,7 +_,7 @@ + int x = (24 + random.nextInt(24)) * (random.nextBoolean() ? -1 : 1); +@@ -80,7 +_,7 @@ - patrollingMonster.setPos(pos.getX(), pos.getY(), pos.getZ()); - patrollingMonster.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.PATROL, null); -- level.addFreshEntityWithPassengers(patrollingMonster); -+ level.addFreshEntityWithPassengers(patrollingMonster, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PATROL); // CraftBukkit + mob.setPos(pos.getX(), pos.getY(), pos.getZ()); + mob.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.PATROL, null); +- level.addFreshEntityWithPassengers(mob); ++ level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PATROL); // CraftBukkit return true; } else { return false; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch index 602489891fc3..86cac164e604 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/levelgen/PhantomSpawner.java +++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java @@ -25,13 +_,22 @@ - public void tick(ServerLevel level, boolean spawnEnemies) { + public void tick(final ServerLevel level, final boolean spawnEnemies) { if (spawnEnemies) { if (level.getGameRules().get(GameRules.SPAWN_PHANTOMS)) { + // Paper start - Ability to control player's insomnia and phantoms @@ -9,28 +9,28 @@ + return; + } + // Paper end - Ability to control player's insomnia and phantoms - RandomSource randomSource = level.random; + RandomSource random = level.getRandom(); this.nextTick--; if (this.nextTick <= 0) { -- this.nextTick = this.nextTick + (60 + randomSource.nextInt(60)) * 20; +- this.nextTick = this.nextTick + (60 + random.nextInt(60)) * 20; + // Paper start - Ability to control player's insomnia and phantoms + int spawnAttemptMinSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMinSeconds; + int spawnAttemptMaxSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; -+ this.nextTick += (spawnAttemptMinSeconds + randomSource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; ++ this.nextTick += (spawnAttemptMinSeconds + random.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; + // Paper end - Ability to control player's insomnia and phantoms if (level.getSkyDarken() >= 5 || !level.dimensionType().hasSkyLight()) { - for (ServerPlayer serverPlayer : level.players()) { -- if (!serverPlayer.isSpectator()) { -+ if (!serverPlayer.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !serverPlayer.isCreative())) { // Paper - Add phantom creative and insomniac controls - BlockPos blockPos = serverPlayer.blockPosition(); - if (!level.dimensionType().hasSkyLight() || blockPos.getY() >= level.getSeaLevel() && level.canSeeSky(blockPos)) { - DifficultyInstance currentDifficultyAt = level.getCurrentDifficultyAt(blockPos); -@@ -50,13 +_,23 @@ - int i2 = 1 + randomSource.nextInt(currentDifficultyAt.getDifficulty().getId() + 1); + for (ServerPlayer player : level.players()) { +- if (!player.isSpectator()) { ++ if (!player.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls + BlockPos playerPos = player.blockPosition(); + if (!level.dimensionType().hasSkyLight() || playerPos.getY() >= level.getSeaLevel() && level.canSeeSky(playerPos)) { + DifficultyInstance difficulty = level.getCurrentDifficultyAt(playerPos); +@@ -50,11 +_,21 @@ + int groupSize = 1 + random.nextInt(difficulty.getDifficulty().getId() + 1); - for (int i3 = 0; i3 < i2; i3++) { + for (int i = 0; i < groupSize; i++) { + // Paper start - PhantomPreSpawnEvent -+ com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent event = new com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos1, level), serverPlayer.getBukkitEntity(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); ++ com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent event = new com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, level), player.getBukkitEntity(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); + if (!event.callEvent()) { + if (event.shouldAbortSpawn()) { + break; @@ -40,11 +40,9 @@ + // Paper end - PhantomPreSpawnEvent Phantom phantom = EntityType.PHANTOM.create(level, EntitySpawnReason.NATURAL); if (phantom != null) { -+ phantom.spawningEntity = serverPlayer.getUUID(); // Paper - PhantomPreSpawnEvent - phantom.snapTo(blockPos1, 0.0F, 0.0F); - spawnGroupData = phantom.finalizeSpawn( - level, currentDifficultyAt, EntitySpawnReason.NATURAL, spawnGroupData - ); ++ phantom.spawningEntity = player.getUUID(); // Paper - PhantomPreSpawnEvent + phantom.snapTo(spawnPos, 0.0F, 0.0F); + groupData = phantom.finalizeSpawn(level, difficulty, EntitySpawnReason.NATURAL, groupData); - level.addFreshEntityWithPassengers(phantom); + level.addFreshEntityWithPassengers(phantom, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/WorldGenerationContext.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/WorldGenerationContext.java.patch index 4bbbbabfb314..392f7a377cc7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/WorldGenerationContext.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/WorldGenerationContext.java.patch @@ -5,16 +5,16 @@ private final int minY; private final int height; + // Paper start - Flat bedrock generator settings -+ private final @javax.annotation.Nullable net.minecraft.world.level.Level serverLevel; ++ private final net.minecraft.world.level.@org.jspecify.annotations.Nullable Level level; - public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor level) { -+ this(generator, level, null); + public WorldGenerationContext(final ChunkGenerator generator, final LevelHeightAccessor heightAccessor) { ++ this(generator, heightAccessor, null); + } -+ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor level, @javax.annotation.Nullable net.minecraft.world.level.Level serverLevel) { -+ this.serverLevel = serverLevel; ++ public WorldGenerationContext(final ChunkGenerator generator, final LevelHeightAccessor heightAccessor, final net.minecraft.world.level.@org.jspecify.annotations.Nullable Level level) { ++ this.level = level; + // Paper end - Flat bedrock generator settings - this.minY = Math.max(level.getMinY(), generator.getMinY()); - this.height = Math.min(level.getHeight(), generator.getGenDepth()); + this.minY = Math.max(heightAccessor.getMinY(), generator.getMinY()); + this.height = Math.min(heightAccessor.getHeight(), generator.getGenDepth()); } @@ -19,4 +_,13 @@ public int getGenDepth() { @@ -23,10 +23,10 @@ + + // Paper start - Flat bedrock generator settings + public net.minecraft.world.level.Level level() { -+ if (this.serverLevel == null) { ++ if (this.level == null) { + throw new NullPointerException("WorldGenerationContext was initialized without a Level, but WorldGenerationContext#level was called"); + } -+ return this.serverLevel; ++ return this.level; + } + // Paper end - Flat bedrock generator settings } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/carver/CarvingContext.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/carver/CarvingContext.java.patch index 63d7237796a3..03efad035a1d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/carver/CarvingContext.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/carver/CarvingContext.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/levelgen/carver/CarvingContext.java +++ b/net/minecraft/world/level/levelgen/carver/CarvingContext.java @@ -27,9 +_,9 @@ - LevelHeightAccessor level, - NoiseChunk noiseChunk, - RandomState randomState, -- SurfaceRules.RuleSource surfaceRule -+ SurfaceRules.RuleSource surfaceRule, @javax.annotation.Nullable net.minecraft.world.level.Level serverLevel // Paper - Flat bedrock generator settings + final LevelHeightAccessor heightAccessor, + final NoiseChunk noiseChunk, + final RandomState randomState, +- final SurfaceRules.RuleSource surfaceRule ++ final SurfaceRules.RuleSource surfaceRule, net.minecraft.world.level.@org.jspecify.annotations.Nullable Level serverLevel // Paper - Flat bedrock generator settings ) { -- super(generator, level); -+ super(generator, level, serverLevel); // Paper - Flat bedrock generator settings +- super(generator, heightAccessor); ++ super(generator, heightAccessor, serverLevel); // Paper - Flat bedrock generator settings this.registryAccess = registryAccess; this.noiseChunk = noiseChunk; this.randomState = randomState; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java.patch index 0d1ce408f040..af4afb034803 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java.patch @@ -3,29 +3,29 @@ @@ -19,6 +_,13 @@ } - public static void createEndPlatform(ServerLevelAccessor level, BlockPos pos, boolean dropBlocks) { + public static void createEndPlatform(final ServerLevelAccessor newLevel, final BlockPos origin, final boolean dropResources) { + // CraftBukkit start -+ createEndPlatform(level, pos, dropBlocks, null); ++ createEndPlatform(newLevel, origin, dropResources, null); + } + -+ public static void createEndPlatform(ServerLevelAccessor level, BlockPos pos, boolean dropBlocks, @javax.annotation.Nullable net.minecraft.world.entity.Entity entity) { -+ org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level); ++ public static void createEndPlatform(final ServerLevelAccessor newLevel, final BlockPos origin, final boolean dropResources, final net.minecraft.world.entity.@org.jspecify.annotations.Nullable Entity entity) { ++ org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(newLevel); + // CraftBukkit end - BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); + BlockPos.MutableBlockPos pos = origin.mutable(); - for (int i = -2; i <= 2; i++) { + for (int dz = -2; dz <= 2; dz++) { @@ -26,15 +_,31 @@ - for (int i2 = -1; i2 < 3; i2++) { - BlockPos blockPos = mutableBlockPos.set(pos).move(i1, i2, i); - Block block = i2 == -1 ? Blocks.OBSIDIAN : Blocks.AIR; -- if (!level.getBlockState(blockPos).is(block)) { + for (int dy = -1; dy < 3; dy++) { + BlockPos blockPos = pos.set(origin).move(dx, dy, dz); + Block block = dy == -1 ? Blocks.OBSIDIAN : Blocks.AIR; +- if (!newLevel.getBlockState(blockPos).is(block)) { + if (!blockList.getBlockState(blockPos).is(block)) { // CraftBukkit - if (dropBlocks) { -- level.destroyBlock(blockPos, true, null); + if (dropResources) { +- newLevel.destroyBlock(blockPos, true, null); + blockList.destroyBlock(blockPos, true, null); // CraftBukkit } -- level.setBlock(blockPos, block.defaultBlockState(), Block.UPDATE_ALL); +- newLevel.setBlock(blockPos, block.defaultBlockState(), Block.UPDATE_ALL); + blockList.setBlock(blockPos, block.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit } } @@ -35,14 +35,14 @@ + // CraftBukkit start + // SPIGOT-7746: Entity will only be null during world generation, which is async, so just generate without event + if (entity != null) { -+ org.bukkit.World bworld = level.getLevel().getWorld(); ++ org.bukkit.World bworld = newLevel.getLevel().getWorld(); + org.bukkit.event.world.PortalCreateEvent portalEvent = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) blockList.getSnapshotBlocks(), bworld, entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM); -+ level.getLevel().getCraftServer().getPluginManager().callEvent(portalEvent); ++ newLevel.getLevel().getCraftServer().getPluginManager().callEvent(portalEvent); + if (portalEvent.isCancelled()) return; + } + -+ if (dropBlocks) { -+ blockList.placeBlocks(state -> level.destroyBlock(state.getPosition(), true, null)); ++ if (dropResources) { ++ blockList.placeBlocks(state -> newLevel.destroyBlock(state.getPosition(), true, null)); + } else { + blockList.placeBlocks(); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/SpikeFeature.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java.patch similarity index 57% rename from paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/SpikeFeature.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java.patch index c36bbede368b..8d9e18233d6a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/SpikeFeature.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java.patch @@ -1,10 +1,10 @@ ---- a/net/minecraft/world/level/levelgen/feature/SpikeFeature.java -+++ b/net/minecraft/world/level/levelgen/feature/SpikeFeature.java -@@ -113,6 +_,7 @@ +--- a/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java ++++ b/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java +@@ -114,6 +_,7 @@ endCrystal.setBeamTarget(config.getCrystalBeamTarget()); endCrystal.setInvulnerable(config.isCrystalInvulnerable()); endCrystal.snapTo(spike.getCenterX() + 0.5, spike.getHeight() + 1, spike.getCenterZ() + 0.5, random.nextFloat() * 360.0F, 0.0F); + endCrystal.generatedByDragonFight = true; // Paper - Fix invulnerable end crystals level.addFreshEntity(endCrystal); - BlockPos blockPosx = endCrystal.blockPosition(); - this.setBlock(level, blockPosx.below(), Blocks.BEDROCK.defaultBlockState()); + BlockPos crystalPos = endCrystal.blockPosition(); + this.setBlock(level, crystalPos.below(), Blocks.BEDROCK.defaultBlockState()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java.patch index f034ad2abba2..45cf44178437 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java +++ b/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java -@@ -26,6 +_,7 @@ +@@ -24,6 +_,7 @@ @Override - public void place(TreeDecorator.Context context) { + public void place(final TreeDecorator.Context context) { + if (context.logs().isEmpty()) return; // Paper - Fix crash when trying to generate without logs - RandomSource randomSource = context.random(); - if (!(randomSource.nextFloat() >= this.probability)) { - List list = context.logs(); + RandomSource random = context.random(); + if (!(random.nextFloat() >= this.probability)) { + List logs = context.logs(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/placement/PlacementContext.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/placement/PlacementContext.java.patch index 1d38b1ee7cc6..82a214358fc5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/placement/PlacementContext.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/placement/PlacementContext.java.patch @@ -3,7 +3,7 @@ @@ -17,7 +_,7 @@ private final Optional topFeature; - public PlacementContext(WorldGenLevel level, ChunkGenerator generator, Optional topFeature) { + public PlacementContext(final WorldGenLevel level, final ChunkGenerator generator, final Optional topFeature) { - super(generator, level); + super(generator, level, level.getLevel()); // Paper - Flat bedrock generator settings this.level = level; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/LegacyStructureDataHandler.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/LegacyStructureDataHandler.java.patch deleted file mode 100644 index a160c1120baf..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/LegacyStructureDataHandler.java.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/net/minecraft/world/level/levelgen/structure/LegacyStructureDataHandler.java -+++ b/net/minecraft/world/level/levelgen/structure/LegacyStructureDataHandler.java -@@ -260,17 +_,18 @@ - } - - public static Supplier getLegacyTagFixer(ResourceKey level, Supplier<@Nullable DimensionDataStorage> storage, DataFixer dataFixer) { -- if (level == Level.OVERWORLD) { -+ ResourceKey stemKey = net.minecraft.core.registries.Registries.levelToLevelStem(level); // CraftBukkit -+ if (stemKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD) { // CraftBukkit - return () -> new LegacyStructureDataHandler( - storage.get(), - ImmutableList.of("Monument", "Stronghold", "Village", "Mineshaft", "Temple", "Mansion"), - ImmutableList.of("Village", "Mineshaft", "Mansion", "Igloo", "Desert_Pyramid", "Jungle_Pyramid", "Swamp_Hut", "Stronghold", "Monument"), - dataFixer - ); -- } else if (level == Level.NETHER) { -+ } else if (stemKey == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - List list = ImmutableList.of("Fortress"); - return () -> new LegacyStructureDataHandler(storage.get(), list, list, dataFixer); -- } else if (level == Level.END) { -+ } else if (stemKey == net.minecraft.world.level.dimension.LevelStem.END) { // CraftBukkit - List list = ImmutableList.of("EndCity"); - return () -> new LegacyStructureDataHandler(storage.get(), list, list, dataFixer); - } else { diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch index 89126f2147fe..f3f18c1d4f9d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch @@ -10,14 +10,14 @@ private final RandomState randomState; private final LevelHeightAccessor heightAccessor; @@ -57,7 +_,7 @@ - ChunkScanAccess storageAccess, - RegistryAccess registryAccess, - StructureTemplateManager structureTemplateManager, -- ResourceKey dimension, -+ ResourceKey dimension, // Paper - fix missing CB diff - ChunkGenerator chunkGenerator, - RandomState randomState, - LevelHeightAccessor heightAccessor, + final ChunkScanAccess storageAccess, + final RegistryAccess registryAccess, + final StructureTemplateManager structureTemplateManager, +- final ResourceKey dimension, ++ final ResourceKey dimension, // Paper - fix missing CB diff + final ChunkGenerator chunkGenerator, + final RandomState randomState, + final LevelHeightAccessor heightAccessor, @@ -77,6 +_,20 @@ this.fixerUpper = fixerUpper; } @@ -36,15 +36,15 @@ + } + // Paper end - add missing structure seed configs + - public StructureCheckResult checkStart(ChunkPos chunkPos, Structure structure, StructurePlacement placement, boolean skipKnownStructures) { - long packedChunkPos = chunkPos.toLong(); - Object2IntMap map = this.loadedChunks.get(packedChunkPos); + public StructureCheckResult checkStart(final ChunkPos pos, final Structure structure, final StructurePlacement placement, final boolean requireUnreferenced) { + long posKey = pos.pack(); + Object2IntMap cachedResult = this.loadedChunks.get(posKey); @@ -86,7 +_,7 @@ - StructureCheckResult structureCheckResult = this.tryLoadFromStorage(chunkPos, structure, skipKnownStructures, packedChunkPos); - if (structureCheckResult != null) { - return structureCheckResult; -- } else if (!placement.applyAdditionalChunkRestrictions(chunkPos.x, chunkPos.z, this.seed)) { -+ } else if (!placement.applyAdditionalChunkRestrictions(chunkPos.x, chunkPos.z, this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs + StructureCheckResult storageCheckResult = this.tryLoadFromStorage(pos, structure, requireUnreferenced, posKey); + if (storageCheckResult != null) { + return storageCheckResult; +- } else if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed)) { ++ } else if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs return StructureCheckResult.START_NOT_PRESENT; } else { - boolean flag = this.featureChecks + boolean isFeatureChunk = this.featureChecks diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructurePiece.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructurePiece.java.patch index 7921171a285f..e71d18ec3648 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructurePiece.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructurePiece.java.patch @@ -1,37 +1,37 @@ --- a/net/minecraft/world/level/levelgen/structure/StructurePiece.java +++ b/net/minecraft/world/level/levelgen/structure/StructurePiece.java -@@ -180,6 +_,11 @@ +@@ -188,6 +_,11 @@ } - level.setBlock(worldPos, state, Block.UPDATE_CLIENTS); -+ // CraftBukkit start - fluid handling is already done if we have a transformer generator access -+ if (level instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess && transformerAccess.canTransformBlocks()) { + level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); ++ // CraftBukkit start - fluid handling is already done if we have a transformer level accessor ++ if (level instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor && transformerAccessor.canTransformBlocks()) { + return; + } + // CraftBukkit end - FluidState fluidState = level.getFluidState(worldPos); + FluidState fluidState = level.getFluidState(pos); if (!fluidState.isEmpty()) { - level.scheduleTick(worldPos, fluidState.getType(), 0); -@@ -192,6 +_,48 @@ + level.scheduleTick(pos, fluidState.getType(), 0); +@@ -200,6 +_,48 @@ } } + // CraftBukkit start + private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); -+ protected boolean placeCraftBlockEntity(ServerLevelAccessor levelAccessor, BlockPos pos, org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState, @Block.UpdateFlags int flags) { -+ if (levelAccessor instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess && transformerAccess.canTransformBlocks()) { -+ return transformerAccess.setCraftBlock(pos, craftBlockEntityState, flags); ++ protected boolean placeCraftBlockEntity(ServerLevelAccessor level, BlockPos pos, org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState, @Block.UpdateFlags int updateFlags) { ++ if (level instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor && transformerAccessor.canTransformBlocks()) { ++ return transformerAccessor.setCraftBlock(pos, craftBlockEntityState, updateFlags); + } + -+ boolean result = levelAccessor.setBlock(pos, craftBlockEntityState.getHandle(), flags); -+ BlockEntity blockEntity = levelAccessor.getBlockEntity(pos); ++ boolean result = level.setBlock(pos, craftBlockEntityState.getHandle(), updateFlags); ++ BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity != null) { + try (final net.minecraft.util.ProblemReporter.ScopedCollector problemReporter = new net.minecraft.util.ProblemReporter.ScopedCollector( + () -> "StructurePieceTranformers@" + pos.toShortString(), LOGGER + )) { + blockEntity.loadWithComponents(net.minecraft.world.level.storage.TagValueInput.create( + problemReporter, -+ levelAccessor.registryAccess(), ++ level.registryAccess(), + craftBlockEntityState.getSnapshotNBT() + )); + } @@ -39,44 +39,44 @@ + return result; + } + -+ protected void placeCraftSpawner(ServerLevelAccessor levelAccessor, BlockPos pos, org.bukkit.entity.EntityType entityType, @Block.UpdateFlags int flags) { ++ protected void placeCraftSpawner(ServerLevelAccessor level, BlockPos pos, org.bukkit.entity.EntityType entityType, @Block.UpdateFlags int updateFlags) { + // This method is used in structures that are generated by code and place spawners as they set the entity after the block was placed making it impossible for plugins to access that information -+ org.bukkit.craftbukkit.block.CraftCreatureSpawner spawner = (org.bukkit.craftbukkit.block.CraftCreatureSpawner) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(levelAccessor, pos, Blocks.SPAWNER.defaultBlockState(), null); ++ org.bukkit.craftbukkit.block.CraftCreatureSpawner spawner = (org.bukkit.craftbukkit.block.CraftCreatureSpawner) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, Blocks.SPAWNER.defaultBlockState(), null); + spawner.setSpawnedType(entityType); -+ this.placeCraftBlockEntity(levelAccessor, pos, spawner, flags); ++ this.placeCraftBlockEntity(level, pos, spawner, updateFlags); + } + -+ protected void setCraftLootTable(ServerLevelAccessor levelAccessor, BlockPos pos, RandomSource randomSource, ResourceKey lootTable) { ++ protected void setCraftLootTable(ServerLevelAccessor level, BlockPos pos, RandomSource randomSource, ResourceKey lootTable) { + // This method is used in structures that use data markers to a loot table to loot containers as otherwise plugins won't have access to that information. -+ net.minecraft.world.level.block.entity.BlockEntity blockEntity = levelAccessor.getBlockEntity(pos); ++ net.minecraft.world.level.block.entity.BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity lootContainerBlockEntity) { + lootContainerBlockEntity.setLootTable(lootTable, randomSource.nextLong()); -+ if (levelAccessor instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess && transformerAccess.canTransformBlocks()) { -+ transformerAccess.setCraftBlock(pos, (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(levelAccessor, pos, blockEntity.getBlockState(), lootContainerBlockEntity.saveWithFullMetadata(levelAccessor.registryAccess())), Block.UPDATE_ALL); ++ if (level instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor && transformerAccessor.canTransformBlocks()) { ++ transformerAccessor.setCraftBlock(pos, (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, blockEntity.getBlockState(), lootContainerBlockEntity.saveWithFullMetadata(level.registryAccess())), Block.UPDATE_ALL); + } + } + } + // CraftBukkit end + - protected boolean canBeReplaced(LevelReader level, int x, int y, int z, BoundingBox box) { + protected boolean canBeReplaced(final LevelReader level, final int x, final int y, final int z, final BoundingBox chunkBB) { return true; } -@@ -420,11 +_,17 @@ - state = reorient(level, pos, Blocks.CHEST.defaultBlockState()); +@@ -471,11 +_,17 @@ + blockState = reorient(level, pos, Blocks.CHEST.defaultBlockState()); } -- level.setBlock(pos, state, Block.UPDATE_CLIENTS); +- level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); - BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof ChestBlockEntity) { - ((ChestBlockEntity)blockEntity).setLootTable(lootTable, random.nextLong()); - } + // CraftBukkit start -+ // level.setBlock(pos, state, Block.UPDATE_CLIENTS); ++ // level.setBlock(pos, blockState, Block.UPDATE_CLIENTS); + // BlockEntity blockEntity = level.getBlockEntity(pos); + // if (blockEntity instanceof ChestBlockEntity) { + // ((ChestBlockEntity)blockEntity).setLootTable(lootTable, random.nextLong()); + // } -+ org.bukkit.craftbukkit.block.CraftChest chestState = (org.bukkit.craftbukkit.block.CraftChest) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, state, null); ++ org.bukkit.craftbukkit.block.CraftChest chestState = (org.bukkit.craftbukkit.block.CraftChest) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, blockState, null); + chestState.setLootTable(org.bukkit.craftbukkit.CraftLootTable.minecraftToBukkit(lootTable)); + chestState.setSeed(random.nextLong()); + this.placeCraftBlockEntity(level, pos, chestState, Block.UPDATE_CLIENTS); @@ -84,18 +84,18 @@ return true; } else { -@@ -437,11 +_,28 @@ +@@ -495,11 +_,28 @@ ) { - BlockPos worldPos = this.getWorldPos(x, y, z); - if (box.isInside(worldPos) && !level.getBlockState(worldPos).is(Blocks.DISPENSER)) { -- this.placeBlock(level, Blocks.DISPENSER.defaultBlockState().setValue(DispenserBlock.FACING, facing), x, y, z, box); -- BlockEntity blockEntity = level.getBlockEntity(worldPos); + BlockPos pos = this.getWorldPos(x, y, z); + if (chunkBB.isInside(pos) && !level.getBlockState(pos).is(Blocks.DISPENSER)) { +- this.placeBlock(level, Blocks.DISPENSER.defaultBlockState().setValue(DispenserBlock.FACING, facing), x, y, z, chunkBB); +- BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof DispenserBlockEntity) { - ((DispenserBlockEntity)blockEntity).setLootTable(lootTable, random.nextLong()); - } + // CraftBukkit start -+ // this.placeBlock(level, Blocks.DISPENSER.defaultBlockState().setValue(DispenserBlock.FACING, facing), x, y, z, box); -+ // BlockEntity blockEntity = level.getBlockEntity(worldPos); ++ // this.placeBlock(level, Blocks.DISPENSER.defaultBlockState().setValue(DispenserBlock.FACING, facing), x, y, z, chunkBB); ++ // BlockEntity blockEntity = level.getBlockEntity(pos); + // if (blockEntity instanceof DispenserBlockEntity) { + // ((DispenserBlockEntity)blockEntity).setLootTable(lootTable, random.nextLong()); + // } @@ -110,10 +110,10 @@ + dispenserBlockState = dispenserBlockState.rotate(this.rotation); + } + -+ org.bukkit.craftbukkit.block.CraftDispenser dispenserState = (org.bukkit.craftbukkit.block.CraftDispenser) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, worldPos, dispenserBlockState, null); ++ org.bukkit.craftbukkit.block.CraftDispenser dispenserState = (org.bukkit.craftbukkit.block.CraftDispenser) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, dispenserBlockState, null); + dispenserState.setLootTable(org.bukkit.craftbukkit.CraftLootTable.minecraftToBukkit(lootTable)); + dispenserState.setSeed(random.nextLong()); -+ this.placeCraftBlockEntity(level, worldPos, dispenserState, Block.UPDATE_CLIENTS); ++ this.placeCraftBlockEntity(level, pos, dispenserState, Block.UPDATE_CLIENTS); + // CraftBukkit end return true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureStart.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureStart.java.patch index c42ee6b4f724..a73e4a06613e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureStart.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureStart.java.patch @@ -10,45 +10,45 @@ + public org.bukkit.event.world.AsyncStructureGenerateEvent.Cause generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.WORLD_GENERATION; + // CraftBukkit end + - public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) { + public StructureStart(final Structure structure, final ChunkPos chunkPos, final int references, final PiecesContainer pieceContainer) { this.structure = structure; this.chunkPos = chunkPos; -@@ -85,11 +_,23 @@ - BlockPos center = boundingBox.getCenter(); - BlockPos blockPos = new BlockPos(center.getX(), boundingBox.minY(), center.getZ()); +@@ -90,11 +_,23 @@ + BlockPos centerPos = centerBB.getCenter(); + BlockPos referencePos = new BlockPos(centerPos.getX(), centerBB.minY(), centerPos.getZ()); -- for (StructurePiece structurePiece : list) { -- if (structurePiece.getBoundingBox().intersects(box)) { -- structurePiece.postProcess(level, structureManager, generator, random, box, chunkPos, blockPos); +- for (StructurePiece next : pieces) { +- if (next.getBoundingBox().intersects(chunkBB)) { +- next.postProcess(level, structureManager, generator, random, chunkBB, chunkPos, referencePos); + // CraftBukkit start -+ // for (StructurePiece structurePiece : list) { -+ // if (structurePiece.getBoundingBox().intersects(box)) { -+ // structurePiece.postProcess(level, structureManager, generator, random, box, chunkPos, blockPos); ++ // for (StructurePiece next : pieces) { ++ // if (next.getBoundingBox().intersects(chunkBB)) { ++ // next.postProcess(level, structureManager, generator, random, chunkBB, chunkPos, referencePos); + // } + // } -+ List pieces = list.stream().filter(piece -> piece.getBoundingBox().intersects(box)).toList(); -+ if (!pieces.isEmpty()) { -+ org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess = new org.bukkit.craftbukkit.util.TransformerGeneratorAccess(); -+ transformerAccess.setDelegate(level); -+ transformerAccess.setStructureTransformer(new org.bukkit.craftbukkit.util.CraftStructureTransformer(this.generationEventCause, level, structureManager, this.structure, box, chunkPos)); -+ for (StructurePiece piece : pieces) { -+ piece.postProcess(transformerAccess, structureManager, generator, random, box, chunkPos, blockPos); ++ List intersectingPieces = pieces.stream().filter(piece -> piece.getBoundingBox().intersects(chunkBB)).toList(); ++ if (!intersectingPieces.isEmpty()) { ++ org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor = new org.bukkit.craftbukkit.util.TransformerLevelAccessor(); ++ transformerAccessor.setDelegate(level); ++ transformerAccessor.setStructureTransformer(new org.bukkit.craftbukkit.util.CraftStructureTransformer(this.generationEventCause, level, structureManager, this.structure, chunkBB, chunkPos)); ++ for (StructurePiece piece : intersectingPieces) { ++ piece.postProcess(transformerAccessor, structureManager, generator, random, chunkBB, chunkPos, referencePos); } -+ transformerAccess.getStructureTransformer().discard(); ++ transformerAccessor.getStructureTransformer().discard(); } + // CraftBukkit end - this.structure.afterPlace(level, structureManager, generator, random, box, chunkPos, this.pieceContainer); + this.structure.afterPlace(level, structureManager, generator, random, chunkBB, chunkPos, this.pieceContainer); } -@@ -97,6 +_,11 @@ +@@ -102,6 +_,11 @@ - public CompoundTag createTag(StructurePieceSerializationContext context, ChunkPos chunkPos) { - CompoundTag compoundTag = new CompoundTag(); + public CompoundTag createTag(final StructurePieceSerializationContext context, final ChunkPos chunkPos) { + CompoundTag tag = new CompoundTag(); + // CraftBukkit start - store persistent data in nbt + if (!this.persistentDataContainer.isEmpty()) { -+ compoundTag.put("StructureBukkitValues", this.persistentDataContainer.toTagCompound()); ++ tag.put("StructureBukkitValues", this.persistentDataContainer.toTagCompound()); + } + // CraftBukkit end if (this.isValid()) { - compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); - compoundTag.putInt("ChunkX", chunkPos.x); + tag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); + tag.putInt("ChunkX", chunkPos.x()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch index 7ddef4667fd1..fa848bf4d8da 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch @@ -5,79 +5,79 @@ } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add missing structure set seed configs - public boolean isStructureChunk(ChunkGeneratorStructureState structureState, int x, int z) { + public boolean isStructureChunk(final ChunkGeneratorStructureState state, final int sourceX, final int sourceZ) { + // Paper start - Add missing structure set seed configs -+ return this.isStructureChunk(structureState, x, z, null); ++ return this.isStructureChunk(state, sourceX, sourceZ, null); + } + -+ public boolean isStructureChunk(ChunkGeneratorStructureState structureState, int x, int z, @javax.annotation.Nullable net.minecraft.resources.ResourceKey structureSetKey) { ++ public boolean isStructureChunk(final ChunkGeneratorStructureState state, final int sourceX, final int sourceZ, final net.minecraft.resources.@org.jspecify.annotations.Nullable ResourceKey structureSetKey) { + Integer saltOverride = null; + if (structureSetKey != null) { + if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.MINESHAFTS) { -+ saltOverride = structureState.conf.mineshaftSeed; ++ saltOverride = state.conf.mineshaftSeed; + } else if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.BURIED_TREASURES) { -+ saltOverride = structureState.conf.buriedTreasureSeed; ++ saltOverride = state.conf.buriedTreasureSeed; + } + } + // Paper end - Add missing structure set seed configs - return this.isPlacementChunk(structureState, x, z) -- && this.applyAdditionalChunkRestrictions(x, z, structureState.getLevelSeed()) -+ && this.applyAdditionalChunkRestrictions(x, z, structureState.getLevelSeed(), saltOverride) // Paper - Add missing structure set seed configs - && this.applyInteractionsWithOtherStructures(structureState, x, z); + return this.isPlacementChunk(state, sourceX, sourceZ) +- && this.applyAdditionalChunkRestrictions(sourceX, sourceZ, state.getLevelSeed()) ++ && this.applyAdditionalChunkRestrictions(sourceX, sourceZ, state.getLevelSeed(), saltOverride) // Paper - Add missing structure set seed configs + && this.applyInteractionsWithOtherStructures(state, sourceX, sourceZ); } -- public boolean applyAdditionalChunkRestrictions(int regionX, int regionZ, long levelSeed) { -- return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(levelSeed, this.salt, regionX, regionZ, this.frequency); +- public boolean applyAdditionalChunkRestrictions(final int sourceX, final int sourceZ, final long levelSeed) { +- return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(levelSeed, this.salt, sourceX, sourceZ, this.frequency); + // Paper start - Add missing structure set seed configs -+ public boolean applyAdditionalChunkRestrictions(int regionX, int regionZ, long levelSeed, @javax.annotation.Nullable Integer saltOverride) { -+ return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(levelSeed, this.salt, regionX, regionZ, this.frequency, saltOverride); ++ public boolean applyAdditionalChunkRestrictions(final int sourceX, final int sourceZ, final long levelSeed, final @org.jspecify.annotations.Nullable Integer saltOverride) { ++ return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(levelSeed, this.salt, sourceX, sourceZ, this.frequency, saltOverride); + // Paper end - Add missing structure set seed configs } - public boolean applyInteractionsWithOtherStructures(ChunkGeneratorStructureState structureState, int x, int z) { + public boolean applyInteractionsWithOtherStructures(final ChunkGeneratorStructureState state, final int sourceX, final int sourceZ) { @@ -101,25 +_,31 @@ public abstract StructurePlacementType type(); -- private static boolean probabilityReducer(long levelSeed, int regionX, int regionZ, int salt, float frequency) { -+ private static boolean probabilityReducer(long levelSeed, int regionX, int regionZ, int salt, float frequency, @javax.annotation.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); - worldgenRandom.setLargeFeatureWithSalt(levelSeed, regionX, regionZ, salt); - return worldgenRandom.nextFloat() < frequency; +- private static boolean probabilityReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability) { ++ private static boolean probabilityReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability, final @org.jspecify.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here + WorldgenRandom random = new WorldgenRandom(new LegacyRandomSource(0L)); + random.setLargeFeatureWithSalt(seed, salt, sourceX, sourceZ); + return random.nextFloat() < probability; } -- private static boolean legacyProbabilityReducerWithDouble(long baseSeed, int salt, int chunkX, int chunkZ, float frequency) { -+ private static boolean legacyProbabilityReducerWithDouble(long baseSeed, int salt, int chunkX, int chunkZ, float frequency, @javax.annotation.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- private static boolean legacyProbabilityReducerWithDouble(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability) { ++ private static boolean legacyProbabilityReducerWithDouble(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability, final @org.jspecify.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs + WorldgenRandom random = new WorldgenRandom(new LegacyRandomSource(0L)); + if (saltOverride == null) { // Paper - Add missing structure set seed configs - worldgenRandom.setLargeFeatureSeed(baseSeed, chunkX, chunkZ); + random.setLargeFeatureSeed(seed, sourceX, sourceZ); + // Paper start - Add missing structure set seed configs + } else { -+ worldgenRandom.setLargeFeatureWithSalt(baseSeed, chunkX, chunkZ, saltOverride); ++ random.setLargeFeatureWithSalt(seed, sourceX, sourceZ, saltOverride); + } + // Paper end - Add missing structure set seed configs - return worldgenRandom.nextDouble() < frequency; + return random.nextDouble() < probability; } -- private static boolean legacyArbitrarySaltProbabilityReducer(long levelSeed, int salt, int regionX, int regionZ, float frequency) { -+ private static boolean legacyArbitrarySaltProbabilityReducer(long levelSeed, int salt, int regionX, int regionZ, float frequency, @javax.annotation.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); -- worldgenRandom.setLargeFeatureWithSalt(levelSeed, regionX, regionZ, 10387320); -+ worldgenRandom.setLargeFeatureWithSalt(levelSeed, regionX, regionZ, saltOverride != null ? saltOverride : HIGHLY_ARBITRARY_RANDOM_SALT); // Paper - Add missing structure set seed configs - return worldgenRandom.nextFloat() < frequency; +- private static boolean legacyArbitrarySaltProbabilityReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability) { ++ private static boolean legacyArbitrarySaltProbabilityReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability, final @org.jspecify.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs + WorldgenRandom random = new WorldgenRandom(new LegacyRandomSource(0L)); +- random.setLargeFeatureWithSalt(seed, sourceX, sourceZ, 10387320); ++ random.setLargeFeatureWithSalt(seed, sourceX, sourceZ, saltOverride != null ? saltOverride : HIGHLY_ARBITRARY_RANDOM_SALT); // Paper - Add missing structure set seed configs + return random.nextFloat() < probability; } -- private static boolean legacyPillagerOutpostReducer(long levelSeed, int salt, int regionX, int regionZ, float frequency) { -+ private static boolean legacyPillagerOutpostReducer(long levelSeed, int salt, int regionX, int regionZ, float frequency, @javax.annotation.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here - int i = regionX >> 4; - int i1 = regionZ >> 4; - WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- private static boolean legacyPillagerOutpostReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability) { ++ private static boolean legacyPillagerOutpostReducer(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability, final @org.jspecify.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here + int cx = sourceX >> 4; + int cz = sourceZ >> 4; + WorldgenRandom random = new WorldgenRandom(new LegacyRandomSource(0L)); @@ -147,7 +_,7 @@ @FunctionalInterface public interface FrequencyReducer { -- boolean shouldGenerate(long levelSeed, int salt, int regionX, int regionZ, float frequency); -+ boolean shouldGenerate(long levelSeed, int salt, int regionX, int regionZ, float frequency, @javax.annotation.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs +- boolean shouldGenerate(long seed, final int salt, final int sourceX, final int sourceZ, float probability); ++ boolean shouldGenerate(long seed, final int salt, final int sourceX, final int sourceZ, float probability, final @org.jspecify.annotations.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs } public static enum FrequencyReductionMethod implements StringRepresentable { @@ -85,10 +85,10 @@ this.reducer = reducer; } -- public boolean shouldGenerate(long levelSeed, int salt, int regionX, int regionZ, float frequency) { -- return this.reducer.shouldGenerate(levelSeed, salt, regionX, regionZ, frequency); -+ public boolean shouldGenerate(long levelSeed, int salt, int regionX, int regionZ, float frequency, @javax.annotation.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs -+ return this.reducer.shouldGenerate(levelSeed, salt, regionX, regionZ, frequency, saltOverride); // Paper - Add missing structure set seed configs +- public boolean shouldGenerate(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability) { +- return this.reducer.shouldGenerate(seed, salt, sourceX, sourceZ, probability); ++ public boolean shouldGenerate(final long seed, final int salt, final int sourceX, final int sourceZ, final float probability, final @org.jspecify.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs ++ return this.reducer.shouldGenerate(seed, salt, sourceX, sourceZ, probability, saltOverride); // Paper - Add missing structure set seed configs } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java.patch index 0d479c6f5e11..c0e388defb0a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java.patch @@ -2,18 +2,18 @@ +++ b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java @@ -66,6 +_,16 @@ - private static void placeSuspiciousSand(BoundingBox boundingBox, WorldGenLevel worldGenLevel, BlockPos pos) { - if (boundingBox.isInside(pos)) { + private static void placeSuspiciousSand(final BoundingBox chunkBB, final WorldGenLevel level, final BlockPos blockPos) { + if (chunkBB.isInside(blockPos)) { + // CraftBukkit start -+ if (worldGenLevel instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess && transformerAccess.canTransformBlocks()) { ++ if (level instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor && transformerAccessor.canTransformBlocks()) { + // todo never called cause it's called in afterPlace after the whole capture logic -+ org.bukkit.craftbukkit.block.CraftBrushableBlock brushableState = (org.bukkit.craftbukkit.block.CraftBrushableBlock) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(worldGenLevel, pos, Blocks.SUSPICIOUS_SAND.defaultBlockState(), null); ++ org.bukkit.craftbukkit.block.CraftBrushableBlock brushableState = (org.bukkit.craftbukkit.block.CraftBrushableBlock) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, blockPos, Blocks.SUSPICIOUS_SAND.defaultBlockState(), null); + brushableState.setLootTable(org.bukkit.craftbukkit.CraftLootTable.minecraftToBukkit(BuiltInLootTables.DESERT_PYRAMID_ARCHAEOLOGY)); -+ brushableState.setSeed(pos.asLong()); -+ transformerAccess.setCraftBlock(pos, brushableState, Block.UPDATE_CLIENTS); ++ brushableState.setSeed(blockPos.asLong()); ++ transformerAccessor.setCraftBlock(blockPos, brushableState, Block.UPDATE_CLIENTS); + return; + } + // CraftBukkit end - worldGenLevel.setBlock(pos, Blocks.SUSPICIOUS_SAND.defaultBlockState(), Block.UPDATE_CLIENTS); - worldGenLevel.getBlockEntity(pos, BlockEntityType.BRUSHABLE_BLOCK) - .ifPresent(brushableBlockEntity -> brushableBlockEntity.setLootTable(BuiltInLootTables.DESERT_PYRAMID_ARCHAEOLOGY, pos.asLong())); + level.setBlock(blockPos, Blocks.SUSPICIOUS_SAND.defaultBlockState(), Block.UPDATE_CLIENTS); + level.getBlockEntity(blockPos, BlockEntityType.BRUSHABLE_BLOCK) + .ifPresent(entity -> entity.setLootTable(BuiltInLootTables.DESERT_PYRAMID_ARCHAEOLOGY, blockPos.asLong())); diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch index a024b0bfebef..c687c69a4d8c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java -@@ -390,7 +_,10 @@ - if (name.startsWith("Chest")) { - BlockPos blockPos = pos.below(); - if (box.isInside(blockPos)) { -- RandomizableContainer.setBlockEntityLootTable(level, random, blockPos, BuiltInLootTables.END_CITY_TREASURE); +@@ -410,7 +_,10 @@ + if (markerId.startsWith("Chest")) { + BlockPos chestPosition = position.below(); + if (chunkBB.isInside(chestPosition)) { +- RandomizableContainer.setBlockEntityLootTable(level, random, chestPosition, BuiltInLootTables.END_CITY_TREASURE); + // CraftBukkit start - ensure block transformation -+ // RandomizableContainer.setBlockEntityLootTable(level, random, blockPos, BuiltInLootTables.END_CITY_TREASURE); -+ this.setCraftLootTable(level, blockPos, random, BuiltInLootTables.END_CITY_TREASURE); ++ // RandomizableContainer.setBlockEntityLootTable(level, random, chestPosition, BuiltInLootTables.END_CITY_TREASURE); ++ this.setCraftLootTable(level, chestPosition, random, BuiltInLootTables.END_CITY_TREASURE); + // CraftBukkit end } - } else if (box.isInside(pos) && Level.isInSpawnableBounds(pos)) { - if (name.startsWith("Sentry")) { + } else if (chunkBB.isInside(position) && Level.isInSpawnableBounds(position)) { + if (markerId.startsWith("Sentry")) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java.patch index 70a17df4e57a..3054f978e67f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/IglooPieces.java -@@ -103,10 +_,13 @@ - protected void handleDataMarker(String name, BlockPos pos, ServerLevelAccessor level, RandomSource random, BoundingBox box) { - if ("chest".equals(name)) { - level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); -- BlockEntity blockEntity = level.getBlockEntity(pos.below()); -- if (blockEntity instanceof ChestBlockEntity) { -- ((ChestBlockEntity)blockEntity).setLootTable(BuiltInLootTables.IGLOO_CHEST, random.nextLong()); +@@ -115,10 +_,13 @@ + ) { + if ("chest".equals(markerId)) { + level.setBlock(position, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); +- BlockEntity chest = level.getBlockEntity(position.below()); +- if (chest instanceof ChestBlockEntity) { +- ((ChestBlockEntity)chest).setLootTable(BuiltInLootTables.IGLOO_CHEST, random.nextLong()); - } + // CraftBukkit start - ensure block transformation -+ // BlockEntity blockEntity = level.getBlockEntity(pos.below()); ++ // BlockEntity blockEntity = level.getBlockEntity(position.below()); + // if (blockEntity instanceof ChestBlockEntity) { + // ((ChestBlockEntity)blockEntity).setLootTable(BuiltInLootTables.IGLOO_CHEST, random.nextLong()); + // } -+ this.setCraftLootTable(level, pos.below(), random, BuiltInLootTables.IGLOO_CHEST); ++ this.setCraftLootTable(level, position.below(), random, BuiltInLootTables.IGLOO_CHEST); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch index 210aa0320b0e..07f0395eff24 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java -@@ -396,10 +_,13 @@ - BlockPos worldPos = this.getWorldPos(1, 0, i8); - if (box.isInside(worldPos) && this.isInterior(level, 1, 0, i8, box)) { +@@ -427,10 +_,13 @@ + BlockPos pos = this.getWorldPos(1, 0, newZ); + if (chunkBB.isInside(pos) && this.isInterior(level, 1, 0, newZ, chunkBB)) { this.hasPlacedSpider = true; -- level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -- if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -- spawnerBlockEntity.setEntityId(EntityType.CAVE_SPIDER, random); +- level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); +- if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { +- spawner.setEntityId(EntityType.CAVE_SPIDER, random); - } + // CraftBukkit start -+ // level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -+ // if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -+ // spawnerBlockEntity.setEntityId(EntityType.CAVE_SPIDER, random); ++ // level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); ++ // if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { ++ // spawner.setEntityId(EntityType.CAVE_SPIDER, random); + // } -+ this.placeCraftSpawner(level, worldPos, org.bukkit.entity.EntityType.CAVE_SPIDER, Block.UPDATE_CLIENTS); ++ this.placeCraftSpawner(level, pos, org.bukkit.entity.EntityType.CAVE_SPIDER, Block.UPDATE_CLIENTS); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch index f167d3222b1b..0b5accdd428d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java -@@ -1084,10 +_,13 @@ - BlockPos worldPos = this.getWorldPos(3, 5, 5); - if (box.isInside(worldPos)) { +@@ -1194,10 +_,13 @@ + BlockPos pos = this.getWorldPos(3, 5, 5); + if (chunkBB.isInside(pos)) { this.hasPlacedSpawner = true; -- level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -- if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -- spawnerBlockEntity.setEntityId(EntityType.BLAZE, random); +- level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); +- if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { +- spawner.setEntityId(EntityType.BLAZE, random); - } + // CraftBukkit start -+ // level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -+ // if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -+ // spawnerBlockEntity.setEntityId(EntityType.BLAZE, random); ++ // level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); ++ // if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { ++ // spawner.setEntityId(EntityType.BLAZE, random); + // } -+ this.placeCraftSpawner(level, worldPos, org.bukkit.entity.EntityType.BLAZE, Block.UPDATE_CLIENTS); ++ this.placeCraftSpawner(level, pos, org.bukkit.entity.EntityType.BLAZE, Block.UPDATE_CLIENTS); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java.patch index 75dc3003e1a4..56eb8a9035a3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java.patch @@ -1,31 +1,35 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java -@@ -308,14 +_,20 @@ - @Override - protected void handleDataMarker(String name, BlockPos pos, ServerLevelAccessor level, RandomSource random, BoundingBox box) { - if ("chest".equals(name)) { +@@ -322,16 +_,22 @@ + final String markerId, final BlockPos position, final ServerLevelAccessor level, final RandomSource random, final BoundingBox chunkBB + ) { + if ("chest".equals(markerId)) { - level.setBlock( -- pos, Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(pos).is(FluidTags.WATER)), Block.UPDATE_CLIENTS +- position, +- Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(position).is(FluidTags.WATER)), +- Block.UPDATE_CLIENTS - ); -- BlockEntity blockEntity = level.getBlockEntity(pos); -- if (blockEntity instanceof ChestBlockEntity) { -- ((ChestBlockEntity)blockEntity) +- BlockEntity chest = level.getBlockEntity(position); +- if (chest instanceof ChestBlockEntity) { +- ((ChestBlockEntity)chest) - .setLootTable(this.isLarge ? BuiltInLootTables.UNDERWATER_RUIN_BIG : BuiltInLootTables.UNDERWATER_RUIN_SMALL, random.nextLong()); - } + // CraftBukkit start - transform block to ensure loot table is accessible + // level.setBlock( -+ // pos, Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(pos).is(FluidTags.WATER)), Block.UPDATE_CLIENTS ++ // position, ++ // Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(position).is(FluidTags.WATER)), ++ // Block.UPDATE_CLIENTS + // ); -+ // BlockEntity blockEntity = level.getBlockEntity(pos); -+ // if (blockEntity instanceof ChestBlockEntity) { -+ // ((ChestBlockEntity)blockEntity) ++ // BlockEntity chest = level.getBlockEntity(position); ++ // if (chest instanceof ChestBlockEntity) { ++ // ((ChestBlockEntity)chest) + // .setLootTable(this.isLarge ? BuiltInLootTables.UNDERWATER_RUIN_BIG : BuiltInLootTables.UNDERWATER_RUIN_SMALL, random.nextLong()); + // } -+ org.bukkit.craftbukkit.block.CraftChest craftChest = (org.bukkit.craftbukkit.block.CraftChest) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, pos, Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(pos).is(FluidTags.WATER)), null); ++ org.bukkit.craftbukkit.block.CraftChest craftChest = (org.bukkit.craftbukkit.block.CraftChest) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, position, Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(position).is(FluidTags.WATER)), null); + craftChest.setSeed(random.nextLong()); + craftChest.setLootTable(org.bukkit.craftbukkit.CraftLootTable.minecraftToBukkit(this.isLarge ? BuiltInLootTables.UNDERWATER_RUIN_BIG : BuiltInLootTables.UNDERWATER_RUIN_SMALL)); -+ this.placeCraftBlockEntity(level, pos, craftChest, Block.UPDATE_CLIENTS); ++ this.placeCraftBlockEntity(level, position, craftChest, Block.UPDATE_CLIENTS); + // CraftBukkit end - } else if ("drowned".equals(name)) { + } else if ("drowned".equals(markerId)) { Drowned drowned = EntityType.DROWNED.create(level.getLevel(), EntitySpawnReason.STRUCTURE); if (drowned != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java.patch index c6cdfce89d83..9e6fd16dfdb1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/ShipwreckPieces.java -@@ -126,7 +_,10 @@ - protected void handleDataMarker(String name, BlockPos pos, ServerLevelAccessor level, RandomSource random, BoundingBox box) { - ResourceKey resourceKey = ShipwreckPieces.MARKERS_TO_LOOT.get(name); - if (resourceKey != null) { -- RandomizableContainer.setBlockEntityLootTable(level, random, pos.below(), resourceKey); +@@ -145,7 +_,10 @@ + ) { + ResourceKey lootTable = ShipwreckPieces.MARKERS_TO_LOOT.get(markerId); + if (lootTable != null) { +- RandomizableContainer.setBlockEntityLootTable(level, random, position.below(), lootTable); + // CraftBukkit start + // RandomizableContainer.setBlockEntityLootTable(level, random, pos.below(), resourceKey); -+ this.setCraftLootTable(level, pos.below(), random, resourceKey); ++ this.setCraftLootTable(level, position.below(), random, lootTable); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch index 6463110c2229..0c701f0b2de2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java -@@ -832,10 +_,13 @@ - BlockPos worldPos = this.getWorldPos(5, 3, 6); - if (box.isInside(worldPos)) { +@@ -898,10 +_,13 @@ + BlockPos pos = this.getWorldPos(5, 3, 6); + if (chunkBB.isInside(pos)) { this.hasPlacedSpawner = true; -- level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -- if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -- spawnerBlockEntity.setEntityId(EntityType.SILVERFISH, random); +- level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); +- if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { +- spawner.setEntityId(EntityType.SILVERFISH, random); - } + // CraftBukkit start -+ // level.setBlock(worldPos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); -+ // if (level.getBlockEntity(worldPos) instanceof SpawnerBlockEntity spawnerBlockEntity) { -+ // spawnerBlockEntity.setEntityId(EntityType.SILVERFISH, random); ++ // level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), Block.UPDATE_CLIENTS); ++ // if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity spawner) { ++ // spawner.setEntityId(EntityType.SILVERFISH, random); + // } -+ this.placeCraftSpawner(level, worldPos, org.bukkit.entity.EntityType.SILVERFISH, Block.UPDATE_CLIENTS); ++ this.placeCraftSpawner(level, pos, org.bukkit.entity.EntityType.SILVERFISH, Block.UPDATE_CLIENTS); + // CraftBukkit end } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java.patch index c2966ef14660..b0dc717a7d77 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java +++ b/net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece.java -@@ -97,7 +_,7 @@ +@@ -103,7 +_,7 @@ witch.setPersistenceRequired(); - witch.snapTo(worldPos.getX() + 0.5, worldPos.getY(), worldPos.getZ() + 0.5, 0.0F, 0.0F); - witch.finalizeSpawn(level, level.getCurrentDifficultyAt(worldPos), EntitySpawnReason.STRUCTURE, null); + witch.snapTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0.0F, 0.0F); + witch.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.STRUCTURE, null); - level.addFreshEntityWithPassengers(witch); + level.addFreshEntityWithPassengers(witch, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason } } } -@@ -116,7 +_,7 @@ +@@ -122,7 +_,7 @@ cat.setPersistenceRequired(); - cat.snapTo(worldPos.getX() + 0.5, worldPos.getY(), worldPos.getZ() + 0.5, 0.0F, 0.0F); - cat.finalizeSpawn(level, level.getCurrentDifficultyAt(worldPos), EntitySpawnReason.STRUCTURE, null); + cat.snapTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0.0F, 0.0F); + cat.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.STRUCTURE, null); - level.addFreshEntityWithPassengers(cat); + level.addFreshEntityWithPassengers(cat, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java.patch index 9ce178ba9c73..8804683011f0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructurePlaceSettings.java.patch @@ -10,16 +10,16 @@ private boolean knownShape; private boolean finalizeEntities; @@ -139,6 +_,13 @@ - int size = palettes.size(); - if (size == 0) { + int paletteSize = palettes.size(); + if (paletteSize == 0) { throw new IllegalStateException("No palettes"); + // CraftBukkit start + } else if (this.palette >= 0) { -+ if (this.palette >= size) { -+ throw new IllegalArgumentException("Palette index out of bounds. Got " + this.palette + " where there are only " + size + " palettes available."); ++ if (this.palette >= paletteSize) { ++ throw new IllegalArgumentException("Palette index out of bounds. Got " + this.palette + " where there are only " + paletteSize + " palettes available."); + } + return palettes.get(this.palette); + // CraftBukkit end } else { - return palettes.get(this.getRandom(pos).nextInt(size)); + return palettes.get(this.getRandom(pos).nextInt(paletteSize)); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch index 0bffaf4763df..7dda6e8c0a52 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch @@ -11,60 +11,68 @@ public Vec3i getSize() { return this.size; -@@ -258,6 +_,19 @@ +@@ -251,7 +_,7 @@ + } + + public boolean placeInWorld( +- final ServerLevelAccessor level, ++ ServerLevelAccessor level, // Paper - make non-final + final BlockPos position, + final BlockPos referencePos, + final StructurePlaceSettings settings, +@@ -261,6 +_,19 @@ if (this.palettes.isEmpty()) { return false; } else { + // CraftBukkit start -+ // We only want the TransformerGeneratorAccess at certain locations because in here are many "block update" calls that shouldn't be transformed -+ ServerLevelAccessor wrappedAccess = level; ++ // We only want the TransformerLevelAccessor at certain locations because in here are many "block update" calls that shouldn't be transformed ++ ServerLevelAccessor wrappedAccessor = level; + org.bukkit.craftbukkit.util.CraftStructureTransformer structureTransformer = null; -+ if (wrappedAccess instanceof org.bukkit.craftbukkit.util.TransformerGeneratorAccess transformerAccess) { -+ level = transformerAccess.getDelegate(); -+ structureTransformer = transformerAccess.getStructureTransformer(); ++ if (wrappedAccessor instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor) { ++ level = transformerAccessor.getDelegate(); ++ structureTransformer = transformerAccessor.getStructureTransformer(); + // The structureTransformer is not needed if we can not transform blocks therefore we can save a little bit of performance doing this + if (structureTransformer != null && !structureTransformer.canTransformBlocks()) { + structureTransformer = null; + } + } + // CraftBukkit end - List list = settings.getRandomPalette(this.palettes, offset).blocks(); - if ((!list.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty()) + List blockInfoList = settings.getRandomPalette(this.palettes, position).blocks(); + if ((!blockInfoList.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty()) && this.size.getX() >= 1 -@@ -285,6 +_,21 @@ +@@ -288,6 +_,20 @@ level.setBlock(blockPos, Blocks.BARRIER.defaultBlockState(), Block.UPDATE_SKIP_ALL_SIDEEFFECTS | Block.UPDATE_NONE); } + // CraftBukkit start + if (structureTransformer != null) { -+ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, blockPos, blockState, null); -+ if (structureBlockInfo.nbt != null && craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState entityState) { -+ entityState.loadData(structureBlockInfo.nbt); ++ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, blockPos, state, null); ++ if (blockInfo.nbt != null && craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState entityState) { ++ entityState.loadData(blockInfo.nbt); + if (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftLootable craftLootable) { + craftLootable.setSeed(random.nextLong()); + } + } + craftBlockState = structureTransformer.transformCraftState(craftBlockState); -+ blockState = craftBlockState.getHandle(); -+ structureBlockInfo = new StructureTemplate.StructureBlockInfo(blockPos, blockState, (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState ? craftBlockEntityState.getSnapshotNBT() : null)); ++ state = craftBlockState.getHandle(); ++ blockInfo = new StructureTemplate.StructureBlockInfo(blockPos, state, (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState ? craftBlockEntityState.getSnapshotNBT() : null)); + } + // CraftBukkit end -+ - if (level.setBlock(blockPos, blockState, flags)) { - i = Math.min(i, blockPos.getX()); - i1 = Math.min(i1, blockPos.getY()); -@@ -296,7 +_,7 @@ - if (structureBlockInfo.nbt != null) { + if (level.setBlock(blockPos, state, updateMode)) { + minX = Math.min(minX, blockPos.getX()); + minY = Math.min(minY, blockPos.getY()); +@@ -299,7 +_,7 @@ + if (blockInfo.nbt != null) { BlockEntity blockEntity = level.getBlockEntity(blockPos); if (blockEntity != null) { - if (!SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { + if (structureTransformer == null && !SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { // CraftBukkit - only process if don't have a transformer access (Was already set above) - SPIGOT-7520: Use structureTransformer as check, so that it is the same as above - structureBlockInfo.nbt.putLong("LootTableSeed", random.nextLong()); + blockInfo.nbt.putLong("LootTableSeed", random.nextLong()); } -@@ -383,7 +_,11 @@ - if (pair1.getSecond() != null) { - BlockEntity blockEntity = level.getBlockEntity(blockPos4); +@@ -384,7 +_,11 @@ + if (blockInfox.getSecond() != null) { + BlockEntity blockEntity = level.getBlockEntity(blockPos); if (blockEntity != null) { - blockEntity.setChanged(); + // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock @@ -75,41 +83,41 @@ } } } -@@ -391,7 +_,7 @@ +@@ -392,7 +_,7 @@ if (!settings.isIgnoreEntities()) { this.placeEntities( - level, -+ wrappedAccess, // CraftBukkit - offset, ++ wrappedAccessor, // CraftBukkit + position, settings.getMirror(), settings.getRotation(), -@@ -504,14 +_,17 @@ +@@ -512,14 +_,17 @@ }); } } + } - private static Optional createEntityIgnoreException(ProblemReporter problemReporter, ServerLevelAccessor level, CompoundTag tag) { + private static Optional createEntityIgnoreException(final ProblemReporter reporter, final ServerLevelAccessor level, final CompoundTag tag) { - try { -- return EntityType.create(TagValueInput.create(problemReporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE); +- return EntityType.create(TagValueInput.create(reporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE); - } catch (Exception var4) { - return Optional.empty(); - } + // CraftBukkit start + // try { -+ return EntityType.create(TagValueInput.create(problemReporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE, true); // Paper - Don't fire sync event during generation ++ return EntityType.create(TagValueInput.create(reporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE, true); // Paper - Don't fire sync event during generation + // } catch (Exception var4) { + // return Optional.empty(); + // } + // CraftBukkit end } - public Vec3i getSize(Rotation rotation) { -@@ -704,6 +_,11 @@ + public Vec3i getSize(final Rotation rotation) { +@@ -710,6 +_,11 @@ - tag.put("entities", listTag3); + tag.put("entities", entityList); tag.put("size", this.newIntegerList(this.size.getX(), this.size.getY(), this.size.getZ())); + // CraftBukkit start - PDC + if (!this.persistentDataContainer.isEmpty()) { @@ -119,10 +127,10 @@ return NbtUtils.addCurrentDataVersion(tag); } -@@ -734,6 +_,11 @@ - .ifPresent(compoundTag1 -> this.entityInfoList.add(new StructureTemplate.StructureEntityInfo(vec3, blockPos, compoundTag1))); - } - ); +@@ -735,6 +_,11 @@ + BlockPos blockPos = new BlockPos(blockPosTag.getIntOr(0, 0), blockPosTag.getIntOr(1, 0), blockPosTag.getIntOr(2, 0)); + entityTag.getCompound("nbt").ifPresent(nbt -> this.entityInfoList.add(new StructureTemplate.StructureEntityInfo(pos, blockPos, nbt))); + }); + // CraftBukkit start - PDC + if (tag.get("BukkitValues") instanceof CompoundTag compoundTag) { + this.persistentDataContainer.putAll(compoundTag); @@ -130,8 +138,8 @@ + // CraftBukkit end } - private void loadPalette(HolderGetter blockGetter, ListTag paletteTag, ListTag blocksTag) { -@@ -833,7 +_,7 @@ + private void loadPalette(final HolderGetter blockLookup, final ListTag paletteList, final ListTag blockList) { +@@ -834,7 +_,7 @@ public static final class Palette { private final List blocks; @@ -139,4 +147,4 @@ + private final Map> cache = Maps.newConcurrentMap(); // Paper - Fix CME due to this collection being shared across threads private @Nullable List cachedJigsaws; - Palette(List blocks) { + private Palette(final List blocks) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch b/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch index f0d1dd9dafcb..adbd1fb3edbd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/material/FlowingFluid.java +++ b/net/minecraft/world/level/material/FlowingFluid.java -@@ -119,6 +_,15 @@ - FluidState newLiquid = this.getNewLiquid(level, blockPos, blockState); - Fluid type = newLiquid.getType(); - if (fluidState1.canBeReplacedWith(level, blockPos, type, Direction.DOWN) && canHoldSpecificFluid(level, blockPos, blockState, type)) { +@@ -121,6 +_,15 @@ + Fluid newBelowFluidType = newBelowFluid.getType(); + if (belowFluid.canBeReplacedWith(level, belowPos, newBelowFluidType, Direction.DOWN) + && canHoldSpecificFluid(level, belowPos, belowState, newBelowFluidType)) { + // CraftBukkit start + org.bukkit.block.Block source = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(source, org.bukkit.block.BlockFace.DOWN); @@ -13,48 +13,48 @@ + return; + } + // CraftBukkit end - this.spreadTo(level, blockPos, blockState, Direction.DOWN, newLiquid); + this.spreadTo(level, belowPos, belowState, Direction.DOWN, newBelowFluid); if (this.sourceNeighborCount(level, pos) >= 3) { this.spreadToSides(level, pos, fluidState, state); -@@ -147,7 +_,18 @@ - Direction direction = entry.getKey(); - FluidState fluidState1 = entry.getValue(); - BlockPos blockPos = pos.relative(direction); -- this.spreadTo(level, blockPos, level.getBlockState(blockPos), direction, fluidState1); -+ final BlockState blockStateIfLoaded = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing -+ if (blockStateIfLoaded == null) continue; // Paper - Prevent chunk loading from fluid flowing +@@ -149,7 +_,18 @@ + Direction spread = entry.getKey(); + FluidState newNeighborFluid = entry.getValue(); + BlockPos neighborPos = pos.relative(spread); +- this.spreadTo(level, neighborPos, level.getBlockState(neighborPos), spread, newNeighborFluid); ++ final BlockState neighborState = level.getBlockStateIfLoaded(neighborPos); // Paper - Prevent chunk loading from fluid flowing ++ if (neighborState == null) continue; // Paper - Prevent chunk loading from fluid flowing + // CraftBukkit start + org.bukkit.block.Block source = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction)); ++ org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(spread)); + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + continue; + } + // CraftBukkit end -+ this.spreadTo(level, blockPos, blockStateIfLoaded, direction, fluidState1); // Paper - Prevent chunk loading from fluid flowing ++ this.spreadTo(level, neighborPos, neighborState, spread, newNeighborFluid); // Paper - Prevent chunk loading from fluid flowing } } } -@@ -159,7 +_,8 @@ +@@ -161,7 +_,8 @@ for (Direction direction : Direction.Plane.HORIZONTAL) { - BlockPos blockPos = mutableBlockPos.setWithOffset(pos, direction); -- BlockState blockState = level.getBlockState(blockPos); -+ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing + BlockPos relativePos = mutablePos.setWithOffset(pos, direction); +- BlockState blockState = level.getBlockState(relativePos); ++ BlockState blockState = level.getBlockStateIfLoaded(relativePos); // Paper - Prevent chunk loading from fluid flowing + if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing FluidState fluidState = blockState.getFluidState(); - if (fluidState.getType().isSame(this) && canPassThroughWall(direction, level, pos, state, blockPos, blockState)) { + if (fluidState.getType().isSame(this) && canPassThroughWall(direction, level, pos, state, relativePos, blockState)) { if (fluidState.isSource()) { -@@ -257,13 +_,15 @@ - liquidBlockContainer.placeLiquid(level, pos, state, fluidState); +@@ -264,13 +_,15 @@ + container.placeLiquid(level, pos, state, target); } else { if (!state.isAir()) { - this.beforeDestroyingBlock(level, pos, state); + this.beforeDestroyingBlock(level, pos, state, pos.relative(direction.getOpposite())); // Paper - Add BlockBreakBlockEvent } - level.setBlock(pos, fluidState.createLegacyBlock(), Block.UPDATE_ALL); + level.setBlock(pos, target.createLegacyBlock(), Block.UPDATE_ALL); } } @@ -62,78 +62,78 @@ + protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state); - protected int getSlopeDistance(LevelReader level, BlockPos pos, int depth, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadContext) { -@@ -272,7 +_,8 @@ - for (Direction direction1 : Direction.Plane.HORIZONTAL) { - if (direction1 != direction) { - BlockPos blockPos = pos.relative(direction1); -- BlockState blockState = spreadContext.getBlockState(blockPos); -+ BlockState blockState = spreadContext.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing -+ if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing - FluidState fluidState = blockState.getFluidState(); - if (this.canPassThrough(level, this.getFlowing(), pos, state, direction1, blockPos, blockState, fluidState)) { - if (spreadContext.isHole(blockPos)) { -@@ -339,7 +_,8 @@ + protected int getSlopeDistance( +@@ -281,7 +_,8 @@ + for (Direction direction : Direction.Plane.HORIZONTAL) { + if (direction != from) { + BlockPos testPos = pos.relative(direction); +- BlockState testState = context.getBlockState(testPos); ++ BlockState testState = context.getBlockStateIfLoaded(testPos); // Paper - Prevent chunk loading from fluid flowing ++ if (testState == null) continue; // Paper - Prevent chunk loading from fluid flowing + FluidState testFluidState = testState.getFluidState(); + if (this.canPassThrough(level, this.getFlowing(), pos, state, direction, testPos, testState, testFluidState)) { + if (context.isHole(testPos)) { +@@ -363,7 +_,8 @@ for (Direction direction : Direction.Plane.HORIZONTAL) { - BlockPos blockPos = pos.relative(direction); -- BlockState blockState = level.getBlockState(blockPos); -+ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing -+ if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing - FluidState fluidState = blockState.getFluidState(); - if (this.canMaybePassThrough(level, pos, state, direction, blockPos, blockState, fluidState)) { - FluidState newLiquid = this.getNewLiquid(level, blockPos, blockState); -@@ -410,10 +_,24 @@ - if (newLiquid.isEmpty()) { - fluidState = newLiquid; - state = Blocks.AIR.defaultBlockState(); + BlockPos testPos = pos.relative(direction); +- BlockState testState = level.getBlockState(testPos); ++ BlockState testState = level.getBlockStateIfLoaded(testPos); // Paper - Prevent chunk loading from fluid flowing ++ if (testState == null) continue; // Paper - Prevent chunk loading from fluid flowing + FluidState testFluidState = testState.getFluidState(); + if (this.canMaybePassThrough(level, pos, state, direction, testPos, testState, testFluidState)) { + FluidState newFluid = this.getNewLiquid(level, testPos, testState); +@@ -434,10 +_,24 @@ + if (newFluidState.isEmpty()) { + fluidState = newFluidState; + blockState = Blocks.AIR.defaultBlockState(); + // CraftBukkit start -+ org.bukkit.event.block.FluidLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFluidLevelChangeEvent(level, pos, state); ++ org.bukkit.event.block.FluidLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFluidLevelChangeEvent(level, pos, blockState); + if (event.isCancelled()) { + return; + } -+ state = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getNewData()).getState(); ++ blockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getNewData()).getState(); + // CraftBukkit end - level.setBlock(pos, state, Block.UPDATE_ALL); - } else if (newLiquid != fluidState) { - fluidState = newLiquid; - state = newLiquid.createLegacyBlock(); + level.setBlock(pos, blockState, Block.UPDATE_ALL); + } else if (newFluidState != fluidState) { + fluidState = newFluidState; + blockState = newFluidState.createLegacyBlock(); + // CraftBukkit start -+ org.bukkit.event.block.FluidLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFluidLevelChangeEvent(level, pos, state); ++ org.bukkit.event.block.FluidLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFluidLevelChangeEvent(level, pos, blockState); + if (event.isCancelled()) { + return; + } -+ state = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getNewData()).getState(); ++ blockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getNewData()).getState(); + // CraftBukkit end - level.setBlock(pos, state, Block.UPDATE_ALL); - level.scheduleTick(pos, newLiquid.getType(), spreadDelay); + level.setBlock(pos, blockState, Block.UPDATE_ALL); + level.scheduleTick(pos, newFluidState.getType(), tickDelay); } -@@ -481,9 +_,27 @@ - public BlockState getBlockState(BlockPos pos) { +@@ -510,8 +_,27 @@ return this.getBlockState(pos, this.getCacheKey(pos)); } + + // Paper start - Prevent chunk loading from fluid flowing -+ public @javax.annotation.Nullable BlockState getBlockStateIfLoaded(BlockPos pos) { ++ public @org.jspecify.annotations.Nullable BlockState getBlockStateIfLoaded(BlockPos pos) { + return this.getBlockState(pos, this.getCacheKey(pos), false); + } + // Paper end - Prevent chunk loading from fluid flowing - - private BlockState getBlockState(BlockPos pos, short cacheKey) { -- return this.stateCache.computeIfAbsent(cacheKey, s -> this.level.getBlockState(pos)); -+ // Paper start - Prevent chunk loading from fluid flowing -+ return getBlockState(pos, cacheKey, true); ++ + private BlockState getBlockState(final BlockPos pos, final short key) { +- return this.stateCache.computeIfAbsent(key, k -> this.level.getBlockState(pos)); ++ // Paper start - Prevent chunk loading from fluid flowing ++ return this.getBlockState(pos, key, true); + } + -+ private @javax.annotation.Nullable BlockState getBlockState(BlockPos pos, short packed, boolean load) { -+ BlockState blockState = this.stateCache.get(packed); ++ private @org.jspecify.annotations.Nullable BlockState getBlockState(final BlockPos pos, final short key, final boolean load) { ++ BlockState blockState = this.stateCache.get(key); + if (blockState == null) { -+ blockState = load ? level.getBlockState(pos) : level.getBlockStateIfLoaded(pos); ++ blockState = load ? this.level.getBlockState(pos) : this.level.getBlockStateIfLoaded(pos); + if (blockState != null) { -+ this.stateCache.put(packed, blockState); ++ this.stateCache.put(key, blockState); + } + } + return blockState; -+ // Paper end - Prevent chunk loading from fluid flowing ++ // Paper end - Prevent chunk loading from fluid flowing } - public boolean isHole(BlockPos pos) { + public boolean isHole(final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/material/FluidState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/material/FluidState.java.patch index 1153a05f33ed..16a6ce9bdd03 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/material/FluidState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/material/FluidState.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/level/material/FluidState.java +++ b/net/minecraft/world/level/material/FluidState.java -@@ -29,9 +_,11 @@ - public static final Codec CODEC = codec(BuiltInRegistries.FLUID.byNameCodec(), Fluid::defaultFluidState).stable(); +@@ -25,9 +_,11 @@ + public static final Codec CODEC = codec(BuiltInRegistries.FLUID.byNameCodec(), Fluid::defaultFluidState, Fluid::getStateDefinition).stable(); public static final int AMOUNT_MAX = 9; public static final int AMOUNT_FULL = 8; + protected final boolean isEmpty; // Paper - Perf: moved from isEmpty() - public FluidState(Fluid owner, Reference2ObjectArrayMap, Comparable> values, MapCodec propertiesCodec) { - super(owner, values, propertiesCodec); + public FluidState(final Fluid owner, final Property[] propertyKeys, final Comparable[] propertyValues) { + super(owner, propertyKeys, propertyValues); + this.isEmpty = owner.isEmpty(); // Paper - Perf: moved from isEmpty() } public Fluid getType() { -@@ -47,7 +_,7 @@ +@@ -43,7 +_,7 @@ } public boolean isEmpty() { @@ -20,4 +20,4 @@ + return this.isEmpty; // Paper - Perf: moved into constructor } - public float getHeight(BlockGetter level, BlockPos pos) { + public float getHeight(final BlockGetter level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch b/paper-server/patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch index daf7d56d473f..af90667de5e3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch @@ -1,38 +1,38 @@ --- a/net/minecraft/world/level/material/LavaFluid.java +++ b/net/minecraft/world/level/material/LavaFluid.java -@@ -94,6 +_,13 @@ - BlockState blockState = level.getBlockState(blockPos); +@@ -95,6 +_,13 @@ + BlockState blockState = level.getBlockState(testPos); if (blockState.isAir()) { - if (this.hasFlammableNeighbours(level, blockPos)) { + if (this.hasFlammableNeighbours(level, testPos)) { + // CraftBukkit start - Prevent lava putting something on fire -+ if (!level.getBlockState(blockPos).is(Blocks.FIRE)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, blockPos, pos).isCancelled()) { ++ if (!level.getBlockState(testPos).is(Blocks.FIRE)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, testPos, pos).isCancelled()) { + continue; + } + } + // CraftBukkit end - level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(level, blockPos)); + level.setBlockAndUpdate(testPos, BaseFireBlock.getState(level, testPos)); return; } -@@ -109,6 +_,14 @@ +@@ -110,6 +_,14 @@ } - if (level.isEmptyBlock(blockPos1.above()) && this.isFlammable(level, blockPos1)) { + if (level.isEmptyBlock(testPos.above()) && this.isFlammable(level, testPos)) { + // CraftBukkit start - Prevent lava putting something on fire -+ BlockPos up = blockPos1.above(); ++ BlockPos up = testPos.above(); + if (!level.getBlockState(up).is(Blocks.FIRE)) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, up, pos).isCancelled()) { + continue; + } + } + // CraftBukkit end - Prevent lava putting something on fire - level.setBlockAndUpdate(blockPos1.above(), BaseFireBlock.getState(level, blockPos1)); + level.setBlockAndUpdate(testPos.above(), BaseFireBlock.getState(level, testPos)); } } -@@ -118,9 +_,10 @@ +@@ -119,9 +_,10 @@ @Override - protected void entityInside(Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) { + protected void entityInside(final Level level, final BlockPos pos, final Entity entity, final InsideBlockEffectApplier effectApplier) { + BlockPos savedPos = pos.immutable(); // Paper - track lava contact effectApplier.apply(InsideBlockEffectType.CLEAR_FREEZE); effectApplier.apply(InsideBlockEffectType.LAVA_IGNITE); @@ -40,10 +40,10 @@ + effectApplier.runAfter(InsideBlockEffectType.LAVA_IGNITE, ignitedEntity -> ignitedEntity.lavaHurt(savedPos)); // Paper - track lava contact } - private boolean hasFlammableNeighbours(LevelReader level, BlockPos pos) { -@@ -207,7 +_,11 @@ - FluidState fluidState1 = level.getFluidState(pos); - if (this.is(FluidTags.LAVA) && fluidState1.is(FluidTags.WATER)) { + private boolean hasFlammableNeighbours(final LevelReader level, final BlockPos pos) { +@@ -208,7 +_,11 @@ + FluidState fluidState = level.getFluidState(pos); + if (this.is(FluidTags.LAVA) && fluidState.is(FluidTags.WATER)) { if (state.getBlock() instanceof LiquidBlock) { - level.setBlock(pos, Blocks.STONE.defaultBlockState(), Block.UPDATE_ALL); + // CraftBukkit start @@ -54,7 +54,7 @@ } this.fizz(level, pos); -@@ -225,7 +_,7 @@ +@@ -226,7 +_,7 @@ @Override protected float getExplosionResistance() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch b/paper-server/patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch index 0accdf667c84..abad32b7d924 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch @@ -5,15 +5,15 @@ } + // Paper start - Add BlockBreakBlockEvent -+ @Override ++ @Override + protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) { + BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; -+ Block.dropResources(state, level, pos, blockEntity, source); ++ Block.dropResources(state, (Level) level, pos, blockEntity, source); + } + // Paper end - Add BlockBreakBlockEvent + @Override - protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state) { + protected void beforeDestroyingBlock(final LevelAccessor level, final BlockPos pos, final BlockState state) { BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; @@ -120,7 +_,7 @@ diff --git a/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch index cacf29e39716..14d2fd86288a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java +++ b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -@@ -477,7 +_,12 @@ +@@ -504,7 +_,12 @@ } - protected static PathType getPathTypeFromState(BlockGetter level, BlockPos pos) { + protected static PathType getPathTypeFromState(final BlockGetter level, final BlockPos pos) { - BlockState blockState = level.getBlockState(pos); + // Paper start - Do not load chunks during pathfinding + BlockState blockState = level.getBlockStateIfLoaded(pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch index 99601fb65303..94746ee3e6ba 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch @@ -5,90 +5,90 @@ } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - public Optional findClosestPortalPosition(BlockPos exitPos, boolean isNether, WorldBorder worldBorder) { + public Optional findClosestPortalPosition(final BlockPos approximateExitPos, final boolean toNether, final WorldBorder worldBorder) { + // CraftBukkit start -+ return this.findClosestPortalPosition(exitPos, worldBorder, isNether ? 16 : 128); // Search Radius ++ return this.findClosestPortalPosition(approximateExitPos, worldBorder, toNether ? 16 : 128); // Search Radius + } + -+ public Optional findClosestPortalPosition(BlockPos exitPos, WorldBorder worldBorder, int i) { ++ public Optional findClosestPortalPosition(final BlockPos approximateExitPos, final WorldBorder worldBorder, final int radius) { PoiManager poiManager = this.level.getPoiManager(); -- int i = isNether ? 16 : 128; -+ // int i = isNether ? 16 : 128; +- int radius = toNether ? 16 : 128; ++ // int radius = toNether ? 16 : 128; + // CraftBukkit end - poiManager.ensureLoadedAndValid(this.level, exitPos, i); - return poiManager.getInSquare(holder -> holder.is(PoiTypes.NETHER_PORTAL), exitPos, i, PoiManager.Occupancy.ANY) + poiManager.ensureLoadedAndValid(this.level, approximateExitPos, radius); + return poiManager.getInSquare(type -> type.is(PoiTypes.NETHER_PORTAL), approximateExitPos, radius, PoiManager.Occupancy.ANY) .map(PoiRecord::getPos) .filter(worldBorder::isWithinBounds) + .filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) // Paper - Configurable nether ceiling damage - .filter(blockPos -> this.level.getBlockState(blockPos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) - .min(Comparator.comparingDouble(blockPos -> blockPos.distSqr(exitPos)).thenComparingInt(Vec3i::getY)); + .filter(pos -> this.level.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) + .min(Comparator.comparingDouble(p -> p.distSqr(approximateExitPos)).thenComparingInt(Vec3i::getY)); } - public Optional createPortal(BlockPos pos, Direction.Axis axis) { + public Optional createPortal(final BlockPos origin, final Direction.Axis portalAxis) { + // CraftBukkit start -+ return this.createPortal(pos, axis, null, 16); ++ return this.createPortal(origin, portalAxis, null, 16); + } + -+ public Optional createPortal(BlockPos pos, Direction.Axis axis, @javax.annotation.Nullable net.minecraft.world.entity.Entity entity, int createRadius) { ++ public Optional createPortal(final BlockPos origin, final Direction.Axis portalAxis, final net.minecraft.world.entity.@org.jspecify.annotations.Nullable Entity entity, final int createRadius) { + // CraftBukkit end - Direction direction = Direction.get(Direction.AxisDirection.POSITIVE, axis); - double d = -1.0; - BlockPos blockPos = null; + Direction direction = Direction.get(Direction.AxisDirection.POSITIVE, portalAxis); + double closestFullDistanceSqr = -1.0; + BlockPos closestFullPosition = null; @@ -58,10 +_,15 @@ - BlockPos blockPos1 = null; + BlockPos closestPartialPosition = null; WorldBorder worldBorder = this.level.getWorldBorder(); - int min = Math.min(this.level.getMaxY(), this.level.getMinY() + this.level.getLogicalHeight() - 1); + int maxPlaceableY = Math.min(this.level.getMaxY(), this.level.getMinY() + this.level.getLogicalHeight() - 1); + // Paper start - Configurable nether ceiling damage; make sure the max height doesn't exceed the void damage height + if (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.enabled()) { -+ min = Math.min(min, this.level.paperConfig().environment.netherCeilingVoidDamageHeight.intValue() - 1); ++ maxPlaceableY = Math.min(maxPlaceableY, this.level.paperConfig().environment.netherCeilingVoidDamageHeight.intValue() - 1); + } + // Paper end - Configurable nether ceiling damage - int i = 1; - BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); + int edgeDistance = 1; + BlockPos.MutableBlockPos mutable = origin.mutable(); -- for (BlockPos.MutableBlockPos mutableBlockPos1 : BlockPos.spiralAround(pos, 16, Direction.EAST, Direction.SOUTH)) { -+ for (BlockPos.MutableBlockPos mutableBlockPos1 : BlockPos.spiralAround(pos, createRadius, Direction.EAST, Direction.SOUTH)) { // CraftBukkit - int min1 = Math.min(min, this.level.getHeight(Heightmap.Types.MOTION_BLOCKING, mutableBlockPos1.getX(), mutableBlockPos1.getZ())); - if (worldBorder.isWithinBounds(mutableBlockPos1) && worldBorder.isWithinBounds(mutableBlockPos1.move(direction, 1))) { - mutableBlockPos1.move(direction.getOpposite(), 1); +- for (BlockPos.MutableBlockPos columnPos : BlockPos.spiralAround(origin, 16, Direction.EAST, Direction.SOUTH)) { ++ for (BlockPos.MutableBlockPos columnPos : BlockPos.spiralAround(origin, createRadius, Direction.EAST, Direction.SOUTH)) { // CraftBukkit + int height = Math.min(maxPlaceableY, this.level.getHeight(Heightmap.Types.MOTION_BLOCKING, columnPos.getX(), columnPos.getZ())); + if (worldBorder.isWithinBounds(columnPos) && worldBorder.isWithinBounds(columnPos.move(direction, 1))) { + columnPos.move(direction.getOpposite(), 1); @@ -105,6 +_,7 @@ - d = d1; + closestFullDistanceSqr = closestPartialDistanceSqr; } + org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(this.level); // CraftBukkit - Use BlockStateListPopulator - if (d == -1.0) { - int max = Math.max(this.level.getMinY() - -1, 70); - int i4 = min - 9; -@@ -123,7 +_,7 @@ - mutableBlockPos.setWithOffset( - blockPos, i2 * direction.getStepX() + i1x * clockWise.getStepX(), i3, i2 * direction.getStepZ() + i1x * clockWise.getStepZ() + if (closestFullDistanceSqr == -1.0) { + int minStartY = Math.max(this.level.getMinY() - -1, 70); + int maxStartY = maxPlaceableY - 9; +@@ -129,7 +_,7 @@ + height, + width * direction.getStepZ() + box * clockWise.getStepZ() ); -- this.level.setBlockAndUpdate(mutableBlockPos, blockState); -+ blockList.setBlock(mutableBlockPos, blockState, Block.UPDATE_ALL); // CraftBukkit +- this.level.setBlockAndUpdate(mutable, blockState); ++ blockList.setBlock(mutable, blockState, Block.UPDATE_ALL); // CraftBukkit } } } -@@ -133,7 +_,7 @@ - for (int i4 = -1; i4 < 4; i4++) { - if (max == -1 || max == 2 || i4 == -1 || i4 == 3) { - mutableBlockPos.setWithOffset(blockPos, max * direction.getStepX(), i4, max * direction.getStepZ()); -- this.level.setBlock(mutableBlockPos, Blocks.OBSIDIAN.defaultBlockState(), Block.UPDATE_ALL); -+ blockList.setBlock(mutableBlockPos, Blocks.OBSIDIAN.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit +@@ -139,7 +_,7 @@ + for (int height = -1; height < 4; height++) { + if (width == -1 || width == 2 || height == -1 || height == 3) { + mutable.setWithOffset(closestFullPosition, width * direction.getStepX(), height, width * direction.getStepZ()); +- this.level.setBlock(mutable, Blocks.OBSIDIAN.defaultBlockState(), Block.UPDATE_ALL); ++ blockList.setBlock(mutable, Blocks.OBSIDIAN.defaultBlockState(), Block.UPDATE_ALL); // CraftBukkit } } } -@@ -143,10 +_,20 @@ - for (int i4x = 0; i4x < 2; i4x++) { - for (int min1 = 0; min1 < 3; min1++) { - mutableBlockPos.setWithOffset(blockPos, i4x * direction.getStepX(), min1, i4x * direction.getStepZ()); -- this.level.setBlock(mutableBlockPos, blockState1, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); -+ blockList.setBlock(mutableBlockPos, blockState1, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit +@@ -149,10 +_,20 @@ + for (int width = 0; width < 2; width++) { + for (int heightx = 0; heightx < 3; heightx++) { + mutable.setWithOffset(closestFullPosition, width * direction.getStepX(), heightx, width * direction.getStepZ()); +- this.level.setBlock(mutable, portalBlockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); ++ blockList.setBlock(mutable, portalBlockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit } } + // CraftBukkit start + org.bukkit.World bworld = this.level.getWorld(); -+ org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) blockList.getSnapshotBlocks(), bworld, (entity == null) ? null : entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.NETHER_PAIR); ++ org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) blockList.getSnapshotBlocks(), bworld, entity == null ? null : entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.NETHER_PAIR); + + this.level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { @@ -96,20 +96,20 @@ + } + blockList.placeBlocks(); + // CraftBukkit end - return Optional.of(new BlockUtil.FoundRectangle(blockPos.immutable(), 2, 3)); + return Optional.of(new BlockUtil.FoundRectangle(closestFullPosition.immutable(), 2, 3)); } -@@ -166,6 +_,13 @@ - i1, - direction.getStepZ() * i + clockWise.getStepZ() * offsetScale +@@ -169,6 +_,13 @@ + mutable.setWithOffset( + origin, direction.getStepX() * width + clockWise.getStepX() * offset, height, direction.getStepZ() * width + clockWise.getStepZ() * offset ); + // Paper start - Protect Bedrock and End Portal/Frames from being destroyed + if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { -+ if (!this.level.getBlockState(offsetPos).isDestroyable()) { ++ if (!this.level.getBlockState(mutable).isDestroyable()) { + return false; + } + } + // Paper end - Protect Bedrock and End Portal/Frames from being destroyed - if (i1 < 0 && !this.level.getBlockState(offsetPos).isSolid()) { + if (height < 0 && !this.level.getBlockState(mutable).isSolid()) { return false; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch index 9b1d58422549..17f9e3ae898f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch @@ -1,143 +1,148 @@ --- a/net/minecraft/world/level/portal/PortalShape.java +++ b/net/minecraft/world/level/portal/PortalShape.java -@@ -38,8 +_,12 @@ +@@ -38,10 +_,14 @@ private final BlockPos bottomLeft; private final int height; private final int width; + // CraftBukkit start - add field + private final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks; -- private PortalShape(Direction.Axis axis, int numPortalBlocks, Direction rightDir, BlockPos bottomLeft, int width, int height) { -+ private PortalShape(Direction.Axis axis, int numPortalBlocks, Direction rightDir, BlockPos bottomLeft, int width, int height, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { + private PortalShape( +- final Direction.Axis axis, final int portalBlockCount, final Direction rightDir, final BlockPos bottomLeft, final int width, final int height ++ final Direction.Axis axis, final int portalBlockCount, final Direction rightDir, final BlockPos bottomLeft, final int width, final int height, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks + ) { + this.blocks = blocks; + // CraftBukkit end this.axis = axis; - this.numPortalBlocks = numPortalBlocks; + this.numPortalBlocks = portalBlockCount; this.rightDir = rightDir; -@@ -63,23 +_,24 @@ +@@ -67,23 +_,24 @@ } - public static PortalShape findAnyShape(BlockGetter level, BlockPos bottomLeft, Direction.Axis axis) { + public static PortalShape findAnyShape(final BlockGetter level, final BlockPos pos, final Direction.Axis axis) { + org.bukkit.craftbukkit.util.BlockStateListPopulator blocks = new org.bukkit.craftbukkit.util.BlockStateListPopulator(((LevelAccessor) level).getMinecraftWorld()); // CraftBukkit - Direction direction = axis == Direction.Axis.X ? Direction.WEST : Direction.SOUTH; -- BlockPos blockPos = calculateBottomLeft(level, direction, bottomLeft); -+ BlockPos blockPos = calculateBottomLeft(level, direction, bottomLeft, blocks); // CraftBukkit - if (blockPos == null) { -- return new PortalShape(axis, 0, direction, bottomLeft, 0, 0); -+ return new PortalShape(axis, 0, direction, bottomLeft, 0, 0, blocks); // CraftBukkit + Direction rightDir = axis == Direction.Axis.X ? Direction.WEST : Direction.SOUTH; +- BlockPos bottomLeft = calculateBottomLeft(level, rightDir, pos); ++ BlockPos bottomLeft = calculateBottomLeft(level, rightDir, pos, blocks); // CraftBukkit + if (bottomLeft == null) { +- return new PortalShape(axis, 0, rightDir, pos, 0, 0); ++ return new PortalShape(axis, 0, rightDir, pos, 0, 0, blocks); // CraftBukkit } else { -- int i = calculateWidth(level, blockPos, direction); -+ int i = calculateWidth(level, blockPos, direction, blocks); // CraftBukkit - if (i == 0) { -- return new PortalShape(axis, 0, direction, blockPos, 0, 0); -+ return new PortalShape(axis, 0, direction, blockPos, 0, 0, blocks); // CraftBukkit +- int width = calculateWidth(level, bottomLeft, rightDir); ++ int width = calculateWidth(level, bottomLeft, rightDir, blocks); // CraftBukkit + if (width == 0) { +- return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0); ++ return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0, blocks); // CraftBukkit } else { - MutableInt mutableInt = new MutableInt(); -- int i1 = calculateHeight(level, blockPos, direction, i, mutableInt); -- return new PortalShape(axis, mutableInt.intValue(), direction, blockPos, i, i1); -+ int i1 = calculateHeight(level, blockPos, direction, i, mutableInt, blocks); // CraftBukkit -+ return new PortalShape(axis, mutableInt.intValue(), direction, blockPos, i, i1, blocks); // CraftBukkit + MutableInt portalBlockCountOutput = new MutableInt(); +- int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput); +- return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height); ++ int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput, blocks); // CraftBukkit ++ return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height, blocks); // CraftBukkit } } } -- private static @Nullable BlockPos calculateBottomLeft(BlockGetter level, Direction direction, BlockPos pos) { -+ private static @Nullable BlockPos calculateBottomLeft(BlockGetter level, Direction direction, BlockPos pos, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit - int max = Math.max(level.getMinY(), pos.getY() - 21); +- private static @Nullable BlockPos calculateBottomLeft(final BlockGetter level, final Direction rightDir, BlockPos pos) { ++ private static @Nullable BlockPos calculateBottomLeft(final BlockGetter level, final Direction rightDir, BlockPos pos, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit + int minY = Math.max(level.getMinY(), pos.getY() - 21); - while (pos.getY() > max && isEmpty(level.getBlockState(pos.below()))) { -@@ -87,16 +_,16 @@ + while (pos.getY() > minY && isEmpty(level.getBlockState(pos.below()))) { +@@ -91,16 +_,16 @@ } - Direction opposite = direction.getOpposite(); -- int i = getDistanceUntilEdgeAboveFrame(level, pos, opposite) - 1; -+ int i = getDistanceUntilEdgeAboveFrame(level, pos, opposite, blocks) - 1; // CraftBukkit - return i < 0 ? null : pos.relative(opposite, i); + Direction leftDir = rightDir.getOpposite(); +- int edge = getDistanceUntilEdgeAboveFrame(level, pos, leftDir) - 1; ++ int edge = getDistanceUntilEdgeAboveFrame(level, pos, leftDir, blocks) - 1; // CraftBukkit + return edge < 0 ? null : pos.relative(leftDir, edge); } -- private static int calculateWidth(BlockGetter level, BlockPos bottomLeft, Direction direction) { -- int distanceUntilEdgeAboveFrame = getDistanceUntilEdgeAboveFrame(level, bottomLeft, direction); -+ private static int calculateWidth(BlockGetter level, BlockPos bottomLeft, Direction direction, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit -+ int distanceUntilEdgeAboveFrame = getDistanceUntilEdgeAboveFrame(level, bottomLeft, direction, blocks); // CraftBukkit - return distanceUntilEdgeAboveFrame >= 2 && distanceUntilEdgeAboveFrame <= 21 ? distanceUntilEdgeAboveFrame : 0; +- private static int calculateWidth(final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir) { +- int width = getDistanceUntilEdgeAboveFrame(level, bottomLeft, rightDir); ++ private static int calculateWidth(final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit ++ int width = getDistanceUntilEdgeAboveFrame(level, bottomLeft, rightDir, blocks); // CraftBukkit + return width >= 2 && width <= 21 ? width : 0; } -- private static int getDistanceUntilEdgeAboveFrame(BlockGetter level, BlockPos pos, Direction direction) { -+ private static int getDistanceUntilEdgeAboveFrame(BlockGetter level, BlockPos pos, Direction direction, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); +- private static int getDistanceUntilEdgeAboveFrame(final BlockGetter level, final BlockPos pos, final Direction direction) { ++ private static int getDistanceUntilEdgeAboveFrame(final BlockGetter level, final BlockPos pos, final Direction direction, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit + BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); - for (int i = 0; i <= 21; i++) { -@@ -104,6 +_,7 @@ - BlockState blockState = level.getBlockState(mutableBlockPos); + for (int width = 0; width <= 21; width++) { +@@ -108,6 +_,7 @@ + BlockState blockState = level.getBlockState(blockPos); if (!isEmpty(blockState)) { - if (FRAME.test(blockState, level, mutableBlockPos)) { -+ blocks.setBlock(mutableBlockPos, blockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - lower left / right - return i; + if (FRAME.test(blockState, level, blockPos)) { ++ blocks.setBlock(blockPos, blockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - lower left / right + return width; } break; -@@ -113,32 +_,34 @@ - if (!FRAME.test(blockState1, level, mutableBlockPos)) { +@@ -117,27 +_,29 @@ + if (!FRAME.test(belowState, level, blockPos)) { break; } -+ blocks.setBlock(mutableBlockPos, blockState1, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - bottom row ++ blocks.setBlock(blockPos, belowState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - bottom row } return 0; } -- private static int calculateHeight(BlockGetter level, BlockPos pos, Direction direction, int width, MutableInt portalBlocks) { -+ private static int calculateHeight(BlockGetter level, BlockPos pos, Direction direction, int width, MutableInt portalBlocks, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); -- int distanceUntilTop = getDistanceUntilTop(level, pos, direction, mutableBlockPos, width, portalBlocks); -- return distanceUntilTop >= 3 && distanceUntilTop <= 21 && hasTopFrame(level, pos, direction, mutableBlockPos, width, distanceUntilTop) -+ int distanceUntilTop = getDistanceUntilTop(level, pos, direction, mutableBlockPos, width, portalBlocks, blocks); // CraftBukkit -+ return distanceUntilTop >= 3 && distanceUntilTop <= 21 && hasTopFrame(level, pos, direction, mutableBlockPos, width, distanceUntilTop, blocks) // CraftBukkit - ? distanceUntilTop - : 0; + private static int calculateHeight( +- final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir, final int width, final MutableInt portalBlockCount ++ final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir, final int width, final MutableInt portalBlockCount, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks // CraftBukkit + ) { + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); +- int height = getDistanceUntilTop(level, bottomLeft, rightDir, pos, width, portalBlockCount); +- return height >= 3 && height <= 21 && hasTopFrame(level, bottomLeft, rightDir, pos, width, height) ? height : 0; ++ int height = getDistanceUntilTop(level, bottomLeft, rightDir, pos, width, portalBlockCount, blocks); // CraftBukkit ++ return height >= 3 && height <= 21 && hasTopFrame(level, bottomLeft, rightDir, pos, width, height, blocks) ? height : 0; // CraftBukkit } -- private static boolean hasTopFrame(BlockGetter level, BlockPos pos, Direction direction, BlockPos.MutableBlockPos checkPos, int width, int distanceUntilTop) { -+ private static boolean hasTopFrame(BlockGetter level, BlockPos pos, Direction direction, BlockPos.MutableBlockPos checkPos, int width, int distanceUntilTop, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks) { // CraftBukkit + private static boolean hasTopFrame( +- final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir, final BlockPos.MutableBlockPos pos, final int width, final int height ++ final BlockGetter level, final BlockPos bottomLeft, final Direction rightDir, final BlockPos.MutableBlockPos pos, final int width, final int height, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks // CraftBukkit + ) { for (int i = 0; i < width; i++) { - BlockPos.MutableBlockPos mutableBlockPos = checkPos.set(pos).move(Direction.UP, distanceUntilTop).move(direction, i); - if (!FRAME.test(level.getBlockState(mutableBlockPos), level, mutableBlockPos)) { + BlockPos.MutableBlockPos framePos = pos.set(bottomLeft).move(Direction.UP, height).move(rightDir, i); + if (!FRAME.test(level.getBlockState(framePos), level, framePos)) { return false; } -+ blocks.setBlock(mutableBlockPos, level.getBlockState(mutableBlockPos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - upper row ++ blocks.setBlock(framePos, level.getBlockState(framePos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit - upper row } return true; - } - - private static int getDistanceUntilTop( -- BlockGetter level, BlockPos pos, Direction direction, BlockPos.MutableBlockPos checkPos, int width, MutableInt portalBlocks -+ BlockGetter level, BlockPos pos, Direction direction, BlockPos.MutableBlockPos checkPos, int width, MutableInt portalBlocks, org.bukkit.craftbukkit.util.BlockStateListPopulator blocks // CraftBukkit +@@ -149,7 +_,7 @@ + final Direction rightDir, + final BlockPos.MutableBlockPos pos, + final int width, +- final MutableInt portalBlockCount ++ final MutableInt portalBlockCount, final org.bukkit.craftbukkit.util.BlockStateListPopulator blocks // CraftBukkit ) { - for (int i = 0; i < 21; i++) { - checkPos.set(pos).move(Direction.UP, i).move(direction, -1); -@@ -162,6 +_,10 @@ - portalBlocks.increment(); + for (int height = 0; height < 21; height++) { + pos.set(bottomLeft).move(Direction.UP, height).move(rightDir, -1); +@@ -173,6 +_,10 @@ + portalBlockCount.increment(); } } + // CraftBukkit start - left and right -+ blocks.setBlock(checkPos.set(pos).move(Direction.UP, i).move(direction, -1), level.getBlockState(checkPos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); -+ blocks.setBlock(checkPos.set(pos).move(Direction.UP, i).move(direction, width), level.getBlockState(checkPos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); ++ blocks.setBlock(pos.set(bottomLeft).move(Direction.UP, height).move(rightDir, -1), level.getBlockState(pos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); ++ blocks.setBlock(pos.set(bottomLeft).move(Direction.UP, height).move(rightDir, width), level.getBlockState(pos), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); + // CraftBukkit end } return 21; -@@ -175,10 +_,23 @@ +@@ -186,10 +_,23 @@ return this.width >= 2 && this.width <= 21 && this.height >= 3 && this.height <= 21; } -- public void createPortalBlocks(LevelAccessor level) { +- public void createPortalBlocks(final LevelAccessor level) { + // CraftBukkit start - return boolean, add entity -+ public boolean createPortalBlocks(LevelAccessor level, Entity entity) { ++ public boolean createPortalBlocks(final LevelAccessor level, final Entity entity) { + org.bukkit.World bworld = level.getMinecraftWorld().getWorld(); + // Copy below for loop - BlockState blockState = Blocks.NETHER_PORTAL.defaultBlockState().setValue(NetherPortalBlock.AXIS, this.axis); + BlockState portalState = Blocks.NETHER_PORTAL.defaultBlockState().setValue(NetherPortalBlock.AXIS, this.axis); BlockPos.betweenClosed(this.bottomLeft, this.bottomLeft.relative(Direction.UP, this.height - 1).relative(this.rightDir, this.width - 1)) -+ .forEach(pos -> this.blocks.setBlock(pos, blockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE)); ++ .forEach(pos -> this.blocks.setBlock(pos, portalState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE)); + org.bukkit.event.world.PortalCreateEvent event = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) this.blocks.getSnapshotBlocks(), bworld, (entity == null) ? null : entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.FIRE); + level.getMinecraftWorld().getServer().server.getPluginManager().callEvent(event); // todo the list is not really mutable here unlike other call and the portal frame is included + @@ -146,7 +151,7 @@ + } + // CraftBukkit end + BlockPos.betweenClosed(this.bottomLeft, this.bottomLeft.relative(Direction.UP, this.height - 1).relative(this.rightDir, this.width - 1)) - .forEach(pos -> level.setBlock(pos, blockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE)); + .forEach(pos -> level.setBlock(pos, portalState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE)); + return true; // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch index e497a2065335..63db595304f0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch @@ -17,15 +17,15 @@ + // CraftBukkit end + public TeleportTransition( - ServerLevel newLevel, Vec3 position, Vec3 deltaMovement, float yRot, float xRot, TeleportTransition.PostTeleportTransition postTeleportTransition + final ServerLevel newLevel, + final Vec3 pos, +@@ -46,7 +_,21 @@ + final Set relatives, + final TeleportTransition.PostTeleportTransition postTeleportTransition ) { -@@ -41,7 +_,21 @@ - Set relatives, - TeleportTransition.PostTeleportTransition postTeleportTransition - ) { -- this(newLevel, position, deltaMovement, yRot, xRot, false, false, relatives, postTeleportTransition); +- this(newLevel, pos, speed, yRot, xRot, false, false, relatives, postTeleportTransition); + // CraftBukkit start -+ this(newLevel, position, deltaMovement, yRot, xRot, relatives, postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); ++ this(newLevel, pos, speed, yRot, xRot, relatives, postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + public TeleportTransition( + ServerLevel newLevel, @@ -41,8 +41,8 @@ + // CraftBukkit end } - private static void playPortalSound(Entity entity) { -@@ -100,7 +_,8 @@ + private static void playPortalSound(final Entity entity) { +@@ -105,7 +_,8 @@ this.missingRespawnBlock(), this.asPassenger(), this.relatives(), @@ -52,7 +52,7 @@ ); } -@@ -114,7 +_,8 @@ +@@ -119,7 +_,8 @@ this.missingRespawnBlock(), this.asPassenger(), this.relatives(), @@ -62,7 +62,7 @@ ); } -@@ -128,7 +_,8 @@ +@@ -133,7 +_,8 @@ this.missingRespawnBlock(), true, this.relatives(), diff --git a/paper-server/patches/sources/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java.patch b/paper-server/patches/sources/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java.patch index bdae25a276df..5fd5b79ef7ef 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -@@ -145,7 +_,7 @@ +@@ -158,7 +_,7 @@ orientation = this.orientation.withFront(direction); } -- NeighborUpdater.executeUpdate(level, blockState, blockPos, this.sourceBlock, orientation, false); -+ NeighborUpdater.executeUpdate(level, blockState, blockPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent +- NeighborUpdater.executeUpdate(level, state, neighborPos, this.sourceBlock, orientation, false); ++ NeighborUpdater.executeUpdate(level, state, neighborPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { this.idx++; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java.patch index 772d6eb81bc4..f7be4cf5d8f9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java +++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java -@@ -18,7 +_,16 @@ - @Override - public void updatePowerStrength(Level level, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean updateShape) { - int i = this.calculateTargetStrength(level, pos); -- if (state.getValue(RedStoneWireBlock.POWER) != i) { +@@ -20,7 +_,16 @@ + final Level level, final BlockPos pos, final BlockState state, final @Nullable Orientation orientation, final boolean skipShapeUpdates + ) { + int targetStrength = this.calculateTargetStrength(level, pos); +- if (state.getValue(RedStoneWireBlock.POWER) != targetStrength) { + // CraftBukkit start + int oldPower = state.getValue(RedStoneWireBlock.POWER); -+ if (oldPower != i) { -+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, i); ++ if (oldPower != targetStrength) { ++ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, targetStrength); + level.getCraftServer().getPluginManager().callEvent(event); + -+ i = event.getNewCurrent(); ++ targetStrength = event.getNewCurrent(); + } -+ if (oldPower != i) { ++ if (oldPower != targetStrength) { + // CraftBukkit end if (level.getBlockState(pos) == state) { - level.setBlock(pos, state.setValue(RedStoneWireBlock.POWER, i), Block.UPDATE_CLIENTS); + level.setBlock(pos, state.setValue(RedStoneWireBlock.POWER, targetStrength), Block.UPDATE_CLIENTS); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java.patch index 15f6e44d7221..e633621dfe80 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java +++ b/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java -@@ -39,7 +_,16 @@ - int intValue = entry.getIntValue(); - int i = unpackPower(intValue); - BlockState blockState = level.getBlockState(blockPos); -- if (blockState.is(this.wireBlock) && !blockState.getValue(RedStoneWireBlock.POWER).equals(i)) { +@@ -45,7 +_,16 @@ + int packed = next.getIntValue(); + int newLevel = unpackPower(packed); + BlockState state = level.getBlockState(pos); +- if (state.is(this.wireBlock) && !state.getValue(RedStoneWireBlock.POWER).equals(newLevel)) { + // CraftBukkit start -+ int oldPower = blockState.getValue(RedStoneWireBlock.POWER); // Paper - Call BlockRedstoneEvent properly; get the previous power from the right state -+ if (oldPower != i) { -+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), oldPower, i); ++ int oldPower = state.getValue(RedStoneWireBlock.POWER); // Paper - Call BlockRedstoneEvent properly; get the previous power from the right state ++ if (oldPower != newLevel) { ++ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, newLevel); + level.getCraftServer().getPluginManager().callEvent(event); + -+ i = event.getNewCurrent(); ++ newLevel = event.getNewCurrent(); + } -+ if (blockState.is(this.wireBlock) && oldPower != i) { ++ if (state.is(this.wireBlock) && oldPower != newLevel) { + // CraftBukkit end - int i1 = Block.UPDATE_CLIENTS; - if (!updateShape || !flag) { - i1 |= Block.UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE; + int updateFlags = Block.UPDATE_CLIENTS; + if (!shapeUpdateWiresAroundInitialPosition || !initialWire) { + updateFlags |= Block.UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE; diff --git a/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch b/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch index fa7488532957..d9bc406db00b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/world/level/redstone/NeighborUpdater.java +++ b/net/minecraft/world/level/redstone/NeighborUpdater.java -@@ -42,8 +_,26 @@ - } - - static void executeUpdate(Level level, BlockState state, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +@@ -66,8 +_,26 @@ + final @Nullable Orientation orientation, + final boolean movedByPiston + ) { + // Paper start - Add source block to BlockPhysicsEvent -+ executeUpdate(level, state, pos, neighborBlock, orientation, movedByPiston, pos); ++ executeUpdate(level, state, pos, changedBlock, orientation, movedByPiston, pos); + } + -+ static void executeUpdate(Level level, BlockState state, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston, BlockPos sourcePos) { ++ static void executeUpdate(Level level, BlockState state, BlockPos pos, Block changedBlock, @Nullable Orientation orientation, boolean movedByPiston, BlockPos sourcePos) { + // Paper end - Add source block to BlockPhysicsEvent try { + // CraftBukkit start -+ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(state), org.bukkit.craftbukkit.block.CraftBlock.at(level, sourcePos)); // Paper - Add source block to BlockPhysicsEvent ++ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.asBlockData(), org.bukkit.craftbukkit.block.CraftBlock.at(level, sourcePos)); // Paper - Add source block to BlockPhysicsEvent + level.getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + // CraftBukkit end - state.handleNeighborChanged(level, pos, neighborBlock, orientation, movedByPiston); + state.handleNeighborChanged(level, pos, changedBlock, orientation, movedByPiston); + // Spigot start + } catch (StackOverflowError ex) { + level.lastPhysicsProblem = pos.immutable(); + // Spigot end } catch (Throwable var9) { - CrashReport crashReport = CrashReport.forThrowable(var9, "Exception while updating neighbours"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Block being updated"); + CrashReport report = CrashReport.forThrowable(var9, "Exception while updating neighbours"); + CrashReportCategory category = report.addCategory("Block being updated"); diff --git a/paper-server/patches/sources/net/minecraft/world/level/saveddata/WeatherData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/saveddata/WeatherData.java.patch new file mode 100644 index 000000000000..93146e5d9de2 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/saveddata/WeatherData.java.patch @@ -0,0 +1,67 @@ +--- a/net/minecraft/world/level/saveddata/WeatherData.java ++++ b/net/minecraft/world/level/saveddata/WeatherData.java +@@ -50,6 +_,25 @@ + } + + public void setThundering(final boolean thundering) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); ++ } ++ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents ++ // CraftBukkit start ++ if (this.thundering == thundering) { ++ return; ++ } ++ ++ org.bukkit.World world = this.level == null ? null : this.level.getWorld(); ++ if (world != null) { ++ org.bukkit.event.weather.ThunderChangeEvent thunder = new org.bukkit.event.weather.ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents ++ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(thunder); ++ if (thunder.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + this.thundering = thundering; + this.setDirty(); + } +@@ -68,6 +_,26 @@ + } + + public void setRaining(final boolean raining) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); ++ } ++ ++ public void setRaining(boolean raining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents ++ // CraftBukkit start ++ if (this.raining == raining) { ++ return; ++ } ++ ++ org.bukkit.World world = this.level == null ? null : this.level.getWorld(); ++ if (world != null) { ++ org.bukkit.event.weather.WeatherChangeEvent weather = new org.bukkit.event.weather.WeatherChangeEvent(world, raining, cause); // Paper - Add cause to Weather/ThunderChangeEvents ++ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(weather); ++ if (weather.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + this.raining = raining; + this.setDirty(); + } +@@ -80,4 +_,11 @@ + this.rainTime = rainTime; + this.setDirty(); + } ++ ++ // Paper start - pass level for events ++ private net.minecraft.server.level.@org.jspecify.annotations.Nullable ServerLevel level; ++ public void setLevel(final net.minecraft.server.level.ServerLevel level) { ++ this.level = level; ++ } ++ // Paper end - pass level for events + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch index 2ac346fb508f..0a014f3cb6c1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -50,7 +_,7 @@ +@@ -48,7 +_,7 @@ private static final String FRAME_PREFIX = "frame-"; public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( -- Level.RESOURCE_KEY_CODEC.fieldOf("dimension").forGetter(mapItemSavedData -> mapItemSavedData.dimension), + i -> i.group( +- Level.RESOURCE_KEY_CODEC.fieldOf("dimension").forGetter(m -> m.dimension), + createUUIDBackedDimensionKeyCodec().forGetter(MapItemSavedData::packUUIDBackedDimension), // Paper - store target world by uuid in addition to dimension - Codec.INT.fieldOf("xCenter").forGetter(mapItemSavedData -> mapItemSavedData.centerX), - Codec.INT.fieldOf("zCenter").forGetter(mapItemSavedData -> mapItemSavedData.centerZ), - Codec.BYTE.optionalFieldOf("scale", (byte)0).forGetter(mapItemSavedData -> mapItemSavedData.scale), -@@ -74,6 +_,7 @@ + Codec.INT.fieldOf("xCenter").forGetter(m -> m.centerX), + Codec.INT.fieldOf("zCenter").forGetter(m -> m.centerZ), + Codec.BYTE.optionalFieldOf("scale", (byte)0).forGetter(m -> m.scale), +@@ -69,6 +_,7 @@ public byte scale; public byte[] colors = new byte[16384]; public boolean locked; @@ -17,7 +17,7 @@ public final List carriedBy = Lists.newArrayList(); public final Map carriedByPlayers = Maps.newHashMap(); private final Map bannerMarkers = Maps.newHashMap(); -@@ -81,6 +_,13 @@ +@@ -76,6 +_,13 @@ private final Map frameMarkers = Maps.newHashMap(); private int trackedDecorationCount; @@ -28,10 +28,10 @@ + public MapId id; + // CraftBukkit end + - public static SavedDataType type(MapId mapId) { - return new SavedDataType<>(mapId.key(), () -> { + public static SavedDataType type(final MapId id) { + return new SavedDataType<>(Identifier.withDefaultNamespace(id.key()), () -> { throw new IllegalStateException("Should never create an empty map saved data"); -@@ -97,7 +_,29 @@ +@@ -98,7 +_,29 @@ this.trackingPosition = trackingPosition; this.unlimitedTracking = unlimitedTracking; this.locked = locked; @@ -61,86 +61,86 @@ + // Paper end - store target world by uuid in addition to dimension private MapItemSavedData( - ResourceKey dimension, -@@ -129,6 +_,8 @@ - MapDecorationTypes.FRAME, null, getFrameKey(mapFrame.entityId()), mapFrame.pos().getX(), mapFrame.pos().getZ(), mapFrame.rotation(), null - ); + final ResourceKey dimension, +@@ -126,6 +_,8 @@ + this.frameMarkers.put(frame.getId(), frame); + this.addDecoration(MapDecorationTypes.FRAME, null, getFrameKey(frame.entityId()), frame.pos().getX(), frame.pos().getZ(), frame.rotation(), null); } + + this.vanillaRender.buffer = colors.array(); // Paper - Use Vanilla map renderer when possible } public static MapItemSavedData createFresh( -@@ -206,6 +_,7 @@ +@@ -209,6 +_,7 @@ } - MapFrame mapFrame1 = new MapFrame(pos, frame.getDirection().get2DDataValue() * 90, frame.getId()); -+ if (this.decorations.size() < player.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps + MapFrame mapFrame = new MapFrame(pos, placedInFrame.getDirection().get2DDataValue() * 90, placedInFrame.getId()); ++ if (this.decorations.size() < tickingPlayer.level().paperConfig().maps.itemFrameCursorLimit) { // Paper - Limit item frame cursors on maps this.addDecoration( - MapDecorationTypes.FRAME, player.level(), getFrameKey(frame.getId()), pos.getX(), pos.getZ(), frame.getDirection().get2DDataValue() * 90, null - ); -@@ -213,6 +_,7 @@ - if (!mapFrame1.equals(mapFrame2)) { + MapDecorationTypes.FRAME, + tickingPlayer.level(), +@@ -222,6 +_,7 @@ + if (!mapFrame.equals(oldFrame)) { this.setDirty(); } + } // Paper - Limit item frame cursors on maps } - MapDecorations mapDecorations = mapStack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY); -@@ -243,7 +_,7 @@ + MapDecorations staticDecorations = itemStack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY); +@@ -252,7 +_,7 @@ this.trackedDecorationCount--; } - this.setDecorationsDirty(); -+ if (mapDecoration != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs ++ if (decoration != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs } - public static void addTargetDecoration(ItemStack stack, BlockPos pos, String type, Holder mapDecorationType) { -@@ -352,7 +_,12 @@ + public static void addTargetDecoration(final ItemStack itemStack, final BlockPos position, final String key, final Holder decorationType) { +@@ -375,7 +_,12 @@ } - public void setColorsDirty(int x, int z) { + public void setColorsDirty(final int x, final int y) { - this.setDirty(); + // Paper start - Fix unnecessary map data saves -+ this.setColorsDirty(x, z, true); ++ this.setColorsDirty(x, y, true); + } -+ public void setColorsDirty(int x, int z, boolean markFileDirty) { ++ public void setColorsDirty(final int x, final int y, final boolean markFileDirty) { + if (markFileDirty) this.setDirty(); + // Paper end - Fix unnecessary map data saves for (MapItemSavedData.HoldingPlayer holdingPlayer : this.carriedBy) { - holdingPlayer.markColorsDirty(x, z); -@@ -393,7 +_,7 @@ + holdingPlayer.markColorsDirty(x, y); +@@ -416,7 +_,7 @@ return true; } - if (!this.isTrackedCountOverLimit(256)) { + if (!this.isTrackedCountOverLimit(((Level) level).paperConfig().maps.itemFrameCursorLimit)) { // Paper - Limit item frame cursors on maps - this.bannerMarkers.put(mapBanner.getId(), mapBanner); - this.addDecoration(mapBanner.getDecoration(), level, mapBanner.getId(), d, d1, 180.0, mapBanner.name().orElse(null)); + this.bannerMarkers.put(banner.getId(), banner); + this.addDecoration(banner.getDecoration(), level, banner.getId(), xPos, zPos, 180.0, banner.name().orElse(null)); this.setDirty(); -@@ -495,7 +_,7 @@ +@@ -524,7 +_,7 @@ this.player = player; } - private MapItemSavedData.MapPatch createPatch() { -+ private MapItemSavedData.MapPatch createPatch(byte[] buffer) { // CraftBukkit - int i = this.minDirtyX; - int i1 = this.minDirtyY; - int i2 = this.maxDirtyX + 1 - this.minDirtyX; -@@ -504,7 +_,7 @@ ++ private MapItemSavedData.MapPatch createPatch(final byte[] buffer) { // CraftBukkit + int startX = this.minDirtyX; + int startY = this.minDirtyY; + int width = this.maxDirtyX + 1 - this.minDirtyX; +@@ -533,7 +_,7 @@ - for (int i4 = 0; i4 < i2; i4++) { - for (int i5 = 0; i5 < i3; i5++) { -- bytes[i4 + i5 * i2] = MapItemSavedData.this.colors[i + i4 + (i1 + i5) * 128]; -+ bytes[i4 + i5 * i2] = buffer[i + i4 + (i1 + i5) * 128]; // CraftBukkit + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { +- patch[x + y * width] = MapItemSavedData.this.colors[startX + x + (startY + y) * 128]; ++ patch[x + y * width] = buffer[startX + x + (startY + y) * 128]; // CraftBukkit } } -@@ -513,17 +_,38 @@ +@@ -542,17 +_,38 @@ - @Nullable Packet nextUpdatePacket(MapId mapId) { - MapItemSavedData.MapPatch mapPatch; + private @Nullable Packet nextUpdatePacket(final MapId id) { + MapItemSavedData.MapPatch patch; + // Paper start + if (!this.dirtyData && this.tick % 5 != 0) { + // this won't end up sending, so don't render it! @@ -154,17 +154,17 @@ + // Paper end if (this.dirtyData) { this.dirtyData = false; -- mapPatch = this.createPatch(); -+ mapPatch = this.createPatch(render.buffer); // CraftBukkit +- patch = this.createPatch(); ++ patch = this.createPatch(render.buffer); // CraftBukkit } else { - mapPatch = null; + patch = null; } - Collection collection; + Collection decorations; - if (this.dirtyDecorations && this.tick++ % 5 == 0) { + if ((!vanillaMaps || this.dirtyDecorations) && this.tick++ % 5 == 0) { // Paper - bypass dirtyDecorations for custom maps this.dirtyDecorations = false; -- collection = MapItemSavedData.this.decorations.values(); +- decorations = MapItemSavedData.this.decorations.values(); + // CraftBukkit start + Collection icons = new java.util.ArrayList<>(); + if (vanillaMaps) this.addSeenPlayers(icons); // Paper @@ -174,12 +174,12 @@ + icons.add(new MapDecoration(org.bukkit.craftbukkit.map.CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(io.papermc.paper.adventure.PaperAdventure.asVanilla(cursor.caption())))); + } + } -+ collection = icons; ++ decorations = icons; + // CraftBukkit end } else { - collection = null; + decorations = null; } -@@ -551,6 +_,23 @@ +@@ -580,6 +_,23 @@ private void markDecorationsDirty() { this.dirtyDecorations = true; } @@ -202,8 +202,8 @@ + // Paper end } - record MapDecorationLocation(Holder type, byte x, byte y, byte rot) { -@@ -595,4 +_,71 @@ + private record MapDecorationLocation(Holder type, byte x, byte y, byte rot) { +@@ -624,4 +_,71 @@ } } } @@ -213,14 +213,14 @@ + + } + record UUIDBackedDimension(@Nullable ResourceKey resourceKey, @Nullable UUIDAndError uuid) { -+ public UUIDBackedDimension(final @org.jetbrains.annotations.NotNull ResourceKey resourceKey) { ++ public UUIDBackedDimension(final ResourceKey resourceKey) { + this(resourceKey, null); + } + public UUIDBackedDimension { + com.google.common.base.Preconditions.checkArgument(resourceKey != null || uuid != null, "Created uuid backed dimension with null level and uuid. This is a bug"); + } + -+ public @org.jetbrains.annotations.NotNull ResourceKey resolveOrThrow() { ++ public ResourceKey resolveOrThrow() { + if (resourceKey != null) return resourceKey; + + final org.bukkit.World worldByUUID = org.bukkit.Bukkit.getWorld(uuid.uuid()); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch deleted file mode 100644 index 81c5212d5251..000000000000 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/level/storage/DimensionDataStorage.java -+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java -@@ -145,7 +_,7 @@ - } else { - int i = Util.maxAllowedExecutorThreads(); - int size = map.size(); -- if (size > i) { -+ if (false && size > i) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue - this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(object -> { - List> list = new ArrayList<>(i); - int i1 = Mth.positiveCeilDiv(size, i); -@@ -166,7 +_,7 @@ - object -> CompletableFuture.allOf( - map.entrySet() - .stream() -- .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) -+ .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool - .toArray(CompletableFuture[]::new) - ) - ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelData.java.patch index 41797a9d2508..24b30413a75c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelData.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/storage/LevelData.java +++ b/net/minecraft/world/level/storage/LevelData.java -@@ -72,5 +_,25 @@ +@@ -62,5 +_,25 @@ public BlockPos pos() { return this.globalPos.pos(); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch index af68b818219b..c10bcfb94a12 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch @@ -1,35 +1,35 @@ --- a/net/minecraft/world/level/storage/LevelStorageSource.java +++ b/net/minecraft/world/level/storage/LevelStorageSource.java -@@ -142,6 +_,7 @@ - PrimaryLevelData primaryLevelData = PrimaryLevelData.parse( - dynamic, levelSettings, complete.specialWorldProperty(), worldGenSettings.options(), lifecycle - ); -+ primaryLevelData.pdc = (Tag) dynamic.getElement("BukkitValues", null); // CraftBukkit - Add PDC to world - return new LevelDataAndDimensions(primaryLevelData, complete); +@@ -169,6 +_,7 @@ + WorldDimensions.Complete dimensions = worldGenSettings.dimensions().bake(datapackDimensions); + Lifecycle lifecycle = dimensions.lifecycle().add(registryAccess.allRegistriesLifecycle()); + PrimaryLevelData worldData = PrimaryLevelData.parse(dataTag, settings, dimensions.specialWorldProperty(), lifecycle); ++ worldData.pdc = (Tag) dataTag.getElement("BukkitValues", null); // CraftBukkit - Add PDC to world + return LevelDataAndDimensions.create(worldData, worldGenSettings, dimensions); + } } - -@@ -336,25 +_,39 @@ +@@ -394,25 +_,39 @@ return this.backupDir; } -- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName) throws IOException, ContentValidationException { -+ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName, ResourceKey dimensionType) throws IOException, ContentValidationException { // CraftBukkit - Path levelPath = this.getLevelPath(saveName); -- List list = this.worldDirValidator.validateDirectory(levelPath, true); -+ List list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(levelPath, true); // Paper - add skipping of symlinks scan - if (!list.isEmpty()) { - throw new ContentValidationException(levelPath, list); +- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(final String levelId) throws IOException, ContentValidationException { ++ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(final String levelId, final ResourceKey dimensionType) throws IOException, ContentValidationException { // CraftBukkit + Path levelPath = this.getLevelPath(levelId); +- List validationResults = this.worldDirValidator.validateDirectory(levelPath, true); ++ List validationResults = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(levelPath, true); // Paper - add skipping of symlinks scan + if (!validationResults.isEmpty()) { + throw new ContentValidationException(levelPath, validationResults); } else { -- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath); -+ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit +- return new LevelStorageSource.LevelStorageAccess(levelId, levelPath); ++ return new LevelStorageSource.LevelStorageAccess(levelId, levelPath, dimensionType); // CraftBukkit } } -- public LevelStorageSource.LevelStorageAccess createAccess(String saveName) throws IOException { -+ public LevelStorageSource.LevelStorageAccess createAccess(String saveName, ResourceKey dimensionType) throws IOException { // CraftBukkit - Path levelPath = this.getLevelPath(saveName); -- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath); -+ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit +- public LevelStorageSource.LevelStorageAccess createAccess(final String levelId) throws IOException { ++ public LevelStorageSource.LevelStorageAccess createAccess(final String levelId, final ResourceKey dimensionType) throws IOException { // CraftBukkit + Path levelPath = this.getLevelPath(levelId); +- return new LevelStorageSource.LevelStorageAccess(levelId, levelPath); ++ return new LevelStorageSource.LevelStorageAccess(levelId, levelPath, dimensionType); // CraftBukkit } public DirectoryValidator getWorldDirValidator() { @@ -53,26 +53,29 @@ public record LevelCandidates(List levels) implements Iterable { public boolean isEmpty() { return this.levels.isEmpty(); -@@ -405,8 +_,12 @@ +@@ -463,11 +_,15 @@ public final LevelStorageSource.LevelDirectory levelDirectory; private final String levelId; - private final Map resources = Maps.newHashMap(); + private final Map resources; + // CraftBukkit start + public final ResourceKey dimensionType; -- LevelStorageAccess(final String levelId, final Path levelDir) throws IOException { -+ LevelStorageAccess(final String levelId, final Path levelDir, final ResourceKey dimensionType) throws IOException { +- private LevelStorageAccess(final String levelId, final Path path) throws IOException { ++ private LevelStorageAccess(final String levelId, final Path path, final ResourceKey dimensionType) throws IOException { + Objects.requireNonNull(LevelStorageSource.this); + super(); + this.resources = Maps.newHashMap(); + this.dimensionType = dimensionType; + // CraftBukkit end this.levelId = levelId; - this.levelDirectory = new LevelStorageSource.LevelDirectory(levelDir); - this.lock = DirectoryLock.create(levelDir); -@@ -449,7 +_,7 @@ + this.levelDirectory = new LevelStorageSource.LevelDirectory(path); + this.createLock(); +@@ -524,7 +_,7 @@ } - public Path getDimensionPath(ResourceKey dimensionPath) { -- return DimensionType.getStorageFolder(dimensionPath, this.levelDirectory.path()); -+ return LevelStorageSource.getStorageFolder(this.levelDirectory.path(), this.dimensionType); // CraftBukkit + public Path getDimensionPath(final ResourceKey name) { +- return DimensionType.getStorageFolder(name, this.levelDirectory.path()); ++ return DimensionType.getStorageFolder(net.minecraft.core.registries.Registries.levelStemToLevel(this.dimensionType), this.levelDirectory.path()); // Paper } private void checkLock() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch index ec0dfb0392aa..3403b87ebef5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch @@ -3,14 +3,14 @@ @@ -31,6 +_,7 @@ } - public void save(Player player) { + public void save(final Player player) { + if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot - try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), LOGGER)) { - TagValueOutput tagValueOutput = TagValueOutput.createWithContext(scopedCollector, player.registryAccess()); - player.saveWithoutId(tagValueOutput); + try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(player.problemPath(), LOGGER)) { + TagValueOutput output = TagValueOutput.createWithContext(reporter, player.registryAccess()); + player.saveWithoutId(output); @@ -42,7 +_,7 @@ - Path path3 = path.resolve(player.getStringUUID() + ".dat_old"); - Util.safeReplaceFile(path2, path1, path3); + Path oldFile = playerDirPath.resolve(player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(realFile, tmpFile, oldFile); } catch (Exception var11) { - LOGGER.warn("Failed to save player data for {}", player.getPlainTextName()); + LOGGER.warn("Failed to save player data for {}", player.getPlainTextName(), var11); // Paper - Print exception @@ -19,25 +19,25 @@ @@ -62,9 +_,25 @@ - private Optional load(NameAndId nameAndId, String suffix) { - File file = new File(this.playerDir, nameAndId.id() + suffix); + private Optional load(final NameAndId nameAndId, final String suffix) { + File realFile = new File(this.playerDir, nameAndId.id() + suffix); + // Spigot start + boolean usingWrongFile = false; -+ if (org.bukkit.Bukkit.getOnlineMode() && !file.exists()) { // Paper - Check online mode first -+ file = new File(this.playerDir, net.minecraft.core.UUIDUtil.createOfflinePlayerUUID(nameAndId.name()) + suffix); -+ if (file.exists()) { ++ if (org.bukkit.Bukkit.getOnlineMode() && !realFile.exists()) { // Paper - Check online mode first ++ realFile = new File(this.playerDir, net.minecraft.core.UUIDUtil.createOfflinePlayerUUID(nameAndId.name()) + suffix); ++ if (realFile.exists()) { + usingWrongFile = true; + LOGGER.warn("Using offline mode UUID file for player {} as it is the only copy we can find.", nameAndId.name()); + } + } + // Spigot end - if (file.exists() && file.isFile()) { + if (realFile.exists() && realFile.isFile()) { try { -- return Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap())); +- return Optional.of(NbtIo.readCompressed(realFile.toPath(), NbtAccounter.unlimitedHeap())); + // Spigot start -+ Optional optional = Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap())); ++ Optional optional = Optional.of(NbtIo.readCompressed(realFile.toPath(), NbtAccounter.unlimitedHeap())); + if (usingWrongFile) { -+ file.renameTo(new File(file.getPath() + ".offline-read")); ++ realFile.renameTo(new File(realFile.getPath() + ".offline-read")); + } + return optional; + // Spigot end @@ -45,7 +45,7 @@ LOGGER.warn("Failed to load player data for {}", nameAndId.name()); } @@ -84,4 +_,10 @@ - return DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, compoundTag, dataVersion); + return DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, tag, version); }); } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch index 75ca0c09e94b..7e477fc5f5cd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch @@ -1,20 +1,19 @@ --- a/net/minecraft/world/level/storage/PrimaryLevelData.java +++ b/net/minecraft/world/level/storage/PrimaryLevelData.java -@@ -48,6 +_,8 @@ +@@ -35,6 +_,8 @@ private final PrimaryLevelData.SpecialWorldProperty specialWorldProperty; private final Lifecycle worldGenSettingsLifecycle; private LevelData.RespawnData respawnData; + private static final String PAPER_RESPAWN_DIMENSION = "paperSpawnDimension"; // Paper + public net.minecraft.resources.ResourceKey respawnDimension = net.minecraft.world.level.Level.OVERWORLD; // Paper private long gameTime; - private long dayTime; - private final @Nullable CompoundTag loadedPlayerTag; -@@ -71,6 +_,21 @@ + private final @Nullable UUID singlePlayerUUID; + private final int version; +@@ -43,6 +_,20 @@ + private boolean wasModded; private final Set removedFeatureFlags; - private final TimerQueue scheduledEvents; + // CraftBukkit start - Add world and pdc -+ public net.minecraft.core.Registry customDimensions; + private net.minecraft.server.level.ServerLevel world; + protected net.minecraft.nbt.Tag pdc; + @@ -29,23 +28,23 @@ + // CraftBukkit end + private PrimaryLevelData( - @Nullable CompoundTag loadedPlayerTag, - boolean wasModded, -@@ -168,7 +_,7 @@ - Lifecycle worldGenSettingsLifecycle + final @Nullable UUID singlePlayerUUID, + final boolean wasModded, +@@ -93,7 +_,7 @@ ) { - long _long = tag.get("Time").asLong(0L); + long gameTime = input.get("Time").asLong(0L); + LevelVersion levelVersion = LevelVersion.parse(input); - return new PrimaryLevelData( + PrimaryLevelData data = new PrimaryLevelData( // Paper - tag.get("Player").flatMap(CompoundTag.CODEC::parse).result().orElse(null), - tag.get("WasModded").asBoolean(false), - tag.get("spawn").read(LevelData.RespawnData.CODEC).result().orElse(LevelData.RespawnData.DEFAULT), -@@ -202,6 +_,13 @@ + input.get("singleplayer_uuid").flatMap(UUIDUtil.CODEC::parse).result().orElse(null), + input.get("WasModded").asBoolean(false), + input.get("spawn").read(LevelData.RespawnData.CODEC).result().orElse(LevelData.RespawnData.DEFAULT), +@@ -106,6 +_,13 @@ specialWorldProperty, worldGenSettingsLifecycle ); + // Paper start -+ data.respawnDimension = tag.get(PAPER_RESPAWN_DIMENSION) ++ data.respawnDimension = input.get(PAPER_RESPAWN_DIMENSION) + .read(net.minecraft.world.level.Level.RESOURCE_KEY_CODEC) + .result() + .orElse(data.respawnData.dimension()); @@ -54,85 +53,27 @@ } @Override -@@ -230,11 +_,12 @@ - tag.put("Version", compoundTag); +@@ -130,6 +_,8 @@ NbtUtils.addCurrentDataVersion(tag); - DynamicOps dynamicOps = registry.createSerializationContext(NbtOps.INSTANCE); -- WorldGenSettings.encode(dynamicOps, this.worldOptions, registry) -+ WorldGenSettings.encode(dynamicOps, this.worldOptions, new net.minecraft.world.level.levelgen.WorldDimensions(this.customDimensions != null ? this.customDimensions : registry.lookupOrThrow(net.minecraft.core.registries.Registries.LEVEL_STEM))) // CraftBukkit - .resultOrPartial(Util.prefix("WorldGenSettings: ", LOGGER::error)) - .ifPresent(worldOptionsTag -> tag.put("WorldGenSettings", worldOptionsTag)); tag.putInt("GameType", this.settings.gameType().getId()); tag.store("spawn", LevelData.RespawnData.CODEC, this.respawnData); ++ // TODO - snapshot - Missing WorldGenSettings.encode diff + tag.store(PAPER_RESPAWN_DIMENSION, net.minecraft.world.level.Level.RESOURCE_KEY_CODEC, this.respawnDimension); // Paper tag.putLong("Time", this.gameTime); - tag.putLong("DayTime", this.dayTime); - tag.putLong("LastPlayed", Util.getEpochMillis()); -@@ -266,6 +_,8 @@ - tag.putInt("WanderingTraderSpawnDelay", this.wanderingTraderSpawnDelay); - tag.putInt("WanderingTraderSpawnChance", this.wanderingTraderSpawnChance); - tag.storeNullable("WanderingTraderId", UUIDUtil.CODEC, this.wanderingTraderId); + writeLastPlayed(tag); + tag.putString("LevelName", this.settings.levelName()); +@@ -142,6 +_,8 @@ + } + + tag.store(WorldDataConfiguration.MAP_CODEC, this.settings.dataConfiguration()); + tag.putString("Bukkit.Version", org.bukkit.Bukkit.getName() + "/" + org.bukkit.Bukkit.getVersion() + "/" + org.bukkit.Bukkit.getBukkitVersion()); // CraftBukkit + this.world.getWorld().storeBukkitValues(tag); // CraftBukkit - add pdc } - private static ListTag stringCollectionToTag(Set stringCollection) { -@@ -336,6 +_,25 @@ - - @Override - public void setThundering(boolean thundering) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); -+ } -+ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents -+ // CraftBukkit start -+ if (this.thundering == thundering) { -+ return; -+ } -+ -+ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName()); -+ if (world != null) { -+ org.bukkit.event.weather.ThunderChangeEvent thunder = new org.bukkit.event.weather.ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents -+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(thunder); -+ if (thunder.isCancelled()) { -+ return; -+ } -+ } -+ // CraftBukkit end - this.thundering = thundering; - } - -@@ -356,6 +_,26 @@ - - @Override - public void setRaining(boolean isRaining) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setRaining(isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); -+ } -+ -+ public void setRaining(boolean isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents -+ // CraftBukkit start -+ if (this.raining == isRaining) { -+ return; -+ } -+ -+ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName()); -+ if (world != null) { -+ org.bukkit.event.weather.WeatherChangeEvent weather = new org.bukkit.event.weather.WeatherChangeEvent(world, isRaining, cause); // Paper - Add cause to Weather/ThunderChangeEvents -+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(weather); -+ if (weather.isCancelled()) { -+ return; -+ } -+ } -+ // CraftBukkit end - this.raining = isRaining; - } - -@@ -422,6 +_,12 @@ + public static void writeLastPlayed(final CompoundTag tag) { +@@ -249,6 +_,12 @@ @Override - public void setDifficulty(Difficulty difficulty) { + public void setDifficulty(final Difficulty difficulty) { this.settings = this.settings.withDifficulty(difficulty); + // CraftBukkit start + net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket packet = new net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket(this.getDifficulty(), this.isDifficultyLocked()); @@ -143,15 +84,15 @@ } @Override -@@ -555,6 +_,14 @@ +@@ -322,6 +_,14 @@ public LevelSettings getLevelSettings() { return this.settings.copy(); } + + // CraftBukkit start - Check if the name stored in NBT is the correct one + public void checkName(String name) { -+ if (!this.settings.levelName.equals(name)) { -+ this.settings.levelName = name; ++ if (!this.settings.levelName().equals(name)) { ++ this.settings = this.settings.withLevelName(name); + } + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch new file mode 100644 index 000000000000..ff0ee4e714cc --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/level/storage/SavedDataStorage.java ++++ b/net/minecraft/world/level/storage/SavedDataStorage.java +@@ -156,7 +_,7 @@ + } else { + int threads = Util.maxAllowedExecutorThreads(); + int taskCount = tagsToSave.size(); +- if (taskCount > threads) { ++ if (false && taskCount > threads) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue + this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(ignored -> { + List> tasks = new ArrayList<>(threads); + int bucketSize = Mth.positiveCeilDiv(taskCount, threads); +@@ -177,7 +_,7 @@ + ignored -> CompletableFuture.allOf( + tagsToSave.entrySet() + .stream() +- .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) ++ .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool + .toArray(CompletableFuture[]::new) + ) + ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueInput.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueInput.java.patch index b53963635f1d..8e21c6bc5380 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueInput.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueInput.java.patch @@ -13,6 +13,6 @@ + } + // Paper end - utility methods + - public static ValueInput create(ProblemReporter problemReporter, HolderLookup.Provider lookup, CompoundTag input) { - return new TagValueInput(problemReporter, new ValueInputContextHelper(lookup, NbtOps.INSTANCE), input); + public static ValueInput create(final ProblemReporter problemReporter, final HolderLookup.Provider holders, final CompoundTag tag) { + return new TagValueInput(problemReporter, new ValueInputContextHelper(holders, NbtOps.INSTANCE), tag); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueOutput.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueOutput.java.patch index ec5028cd5812..08b6e862af3a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueOutput.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/TagValueOutput.java.patch @@ -21,6 +21,6 @@ + } + // Paper end - utility methods + - public static TagValueOutput createWithContext(ProblemReporter problemReporter, HolderLookup.Provider lookup) { - return new TagValueOutput(problemReporter, lookup.createSerializationContext(NbtOps.INSTANCE), new CompoundTag()); + public static TagValueOutput createWithContext(final ProblemReporter problemReporter, final HolderLookup.Provider provider) { + return new TagValueOutput(problemReporter, provider.createSerializationContext(NbtOps.INSTANCE), new CompoundTag()); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootDataType.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootDataType.java.patch index 0b8df8cc19cd..7006279d9f7b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootDataType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootDataType.java.patch @@ -1,20 +1,14 @@ --- a/net/minecraft/world/level/storage/loot/LootDataType.java +++ b/net/minecraft/world/level/storage/loot/LootDataType.java -@@ -32,9 +_,14 @@ - } - - private static LootDataType.Validator createLootTableValidator() { -- return (context, key, value) -> value.validate( -- context.setContextKeySet(value.getParamSet()).enterElement(new ProblemReporter.RootElementPathElement(key), key) -- ); +@@ -26,6 +_,11 @@ + ContextKeySet contextKeys = this.contextGetter.context(value); + ValidationContext rootContext = contextSource.context(contextKeys).enterElement(new ProblemReporter.RootElementPathElement(key), key); + value.validate(rootContext); + // CraftBukkit start -+ return (context, key, value) -> { -+ value.validate( -+ context.setContextKeySet(value.getParamSet()).enterElement(new ProblemReporter.RootElementPathElement(key), key) -+ ); -+ value.craftLootTable = new org.bukkit.craftbukkit.CraftLootTable(org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(key.identifier()), value); -+ // CraftBukkit end -+ }; ++ if (value instanceof LootTable lootTable) { ++ lootTable.craftLootTable = new org.bukkit.craftbukkit.CraftLootTable(org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(key.identifier()), lootTable); ++ } ++ // CraftBukkit end } - @FunctionalInterface + public void runValidation(final ValidationContextSource contextSource, final HolderLookup lookup) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootTable.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootTable.java.patch index 3e2647744fbb..d8cc204c17b9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootTable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/LootTable.java.patch @@ -1,46 +1,46 @@ --- a/net/minecraft/world/level/storage/loot/LootTable.java +++ b/net/minecraft/world/level/storage/loot/LootTable.java -@@ -53,6 +_,7 @@ +@@ -52,6 +_,7 @@ private final List pools; private final List functions; private final BiFunction compositeFunction; + public org.bukkit.craftbukkit.CraftLootTable craftLootTable; // CraftBukkit - LootTable(ContextKeySet paramSet, Optional randomSequence, List pools, List functions) { - this.paramSet = paramSet; -@@ -63,9 +_,10 @@ + private LootTable( + final ContextKeySet paramSet, final Optional randomSequence, final List pools, final List functions +@@ -64,9 +_,10 @@ } - public static Consumer createStackSplitter(ServerLevel level, Consumer output) { + public static Consumer createStackSplitter(final ServerLevel level, final Consumer output) { + boolean skipSplitter = level != null && !level.paperConfig().fixes.splitOverstackedLoot; // Paper - preserve overstacked items - return itemStack -> { - if (itemStack.isItemEnabled(level.enabledFeatures())) { -- if (itemStack.getCount() < itemStack.getMaxStackSize()) { -+ if (skipSplitter || itemStack.getCount() < itemStack.getMaxStackSize()) { // Paper - preserve overstacked items - output.accept(itemStack); + return result -> { + if (result.isItemEnabled(level.enabledFeatures())) { +- if (result.getCount() < result.getMaxStackSize()) { ++ if (skipSplitter || result.getCount() < result.getMaxStackSize()) { // Paper - preserve overstacked items + output.accept(result); } else { - int count = itemStack.getCount(); -@@ -146,9 +_,22 @@ + int count = result.getCount(); +@@ -144,9 +_,22 @@ } - public void fill(Container container, LootParams params, long seed) { -- LootContext lootContext = new LootContext.Builder(params).withOptionalRandomSeed(seed).create(this.randomSequence); + public void fill(final Container container, final LootParams params, final long optionalRandomSeed) { +- LootContext context = new LootContext.Builder(params).withOptionalRandomSeed(optionalRandomSeed).create(this.randomSequence); + // CraftBukkit start -+ this.fill(container, params, seed == 0L ? null : RandomSource.create(seed), false); ++ this.fill(container, params, optionalRandomSeed == 0L ? null : RandomSource.create(optionalRandomSeed), false); + } + + public void fill(Container container, LootParams params, RandomSource randomSource, boolean plugin) { + // CraftBukkit end -+ LootContext lootContext = new LootContext.Builder(params).withOptionalRandomSource(randomSource).create(this.randomSequence); - ObjectArrayList randomItems = this.getRandomItems(lootContext); - RandomSource random = lootContext.getRandom(); ++ LootContext context = new LootContext.Builder(params).withOptionalRandomSource(randomSource).create(this.randomSequence); + ObjectArrayList itemStacks = this.getRandomItems(context); + RandomSource random = context.getRandom(); + // CraftBukkit start -+ org.bukkit.event.world.LootGenerateEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLootGenerateEvent(container, this, lootContext, randomItems, plugin); ++ org.bukkit.event.world.LootGenerateEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLootGenerateEvent(container, this, context, itemStacks, plugin); + if (event.isCancelled()) { + return; + } -+ randomItems = event.getLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).collect(ObjectArrayList.toList()); ++ itemStacks = event.getLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).collect(ObjectArrayList.toList()); + // CraftBukkit end List availableSlots = this.getAvailableSlots(container, random); - this.shuffleAndSplitItems(randomItems, availableSlots.size(), random); + this.shuffleAndSplitItems(itemStacks, availableSlots.size(), random); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch index 03a917ef41ea..6124d48cb417 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java +++ b/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java -@@ -33,6 +_,10 @@ +@@ -39,6 +_,10 @@ ); } }; @@ -9,12 +9,12 @@ + private int lastWeight; + // Paper end - Configurable LootPool luck formula - protected LootPoolSingletonContainer(int weight, int quality, List conditions, List functions) { + protected LootPoolSingletonContainer(final int weight, final int quality, final List conditions, final List functions) { super(conditions); -@@ -127,7 +_,31 @@ - protected abstract class EntryBase implements LootPoolEntry { +@@ -135,7 +_,31 @@ + @Override - public int getWeight(float luck) { + public int getWeight(final float luck) { - return Math.max(Mth.floor(LootPoolSingletonContainer.this.weight + LootPoolSingletonContainer.this.quality * luck), 0); + // Paper start - Configurable LootPool luck formula + // SEE: https://luckformula.emc.gs for details and data diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch index 8aa494bf04f6..8862d67128e3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch @@ -1,20 +1,30 @@ --- a/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java +++ b/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java -@@ -87,7 +_,16 @@ - Vec3 vec3 = context.getOptionalParameter(LootContextParams.ORIGIN); - if (vec3 != null) { +@@ -83,9 +_,25 @@ + Vec3 lootPos = context.getOptionalParameter(LootContextParams.ORIGIN); + if (lootPos != null) { ServerLevel level = context.getLevel(); -- BlockPos blockPos = level.findNearestMapStructure(this.destination, BlockPos.containing(vec3), this.searchRadius, this.skipKnownStructures); + // Paper start - Configurable cartographer treasure maps ++ // Simple heuristic for determining if this function is running in the context of a villager selecting ++ // an item for its offers. Technically other callers could satisfiy this but this minimises the diff and ++ // works for all plain vanilla usecases. ++ final boolean runningForVillagerTrade = context.hasParameter(LootContextParams.ADDITIONAL_COST_COMPONENT_ALLOWED) ++ && context.getOptionalParameter(LootContextParams.THIS_ENTITY) instanceof net.minecraft.world.entity.npc.villager.AbstractVillager; + if (!level.paperConfig().environment.treasureMaps.enabled) { + /* + * NOTE: I fear users will just get a plain map as their "treasure" + * This is preferable to disrespecting the config. + */ -+ return stack; ++ return runningForVillagerTrade ? net.minecraft.world.item.ItemStack.EMPTY : itemStack; + } ++ final boolean shouldSkipKnownStructures = runningForVillagerTrade ++ ? !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager ++ : !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(!this.skipKnownStructures); + // Paper end - Configurable cartographer treasure maps -+ BlockPos blockPos = level.findNearestMapStructure(this.destination, BlockPos.containing(vec3), this.searchRadius, !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(!this.skipKnownStructures)); // Paper - Configurable cartographer treasure maps - if (blockPos != null) { - ItemStack itemStack = MapItem.create(level, blockPos.getX(), blockPos.getZ(), this.zoom, true, true); - MapItem.renderBiomePreviewMap(level, itemStack); + BlockPos nearestMapStructure = level.findNearestMapStructure( +- this.destination, BlockPos.containing(lootPos), this.searchRadius, this.skipKnownStructures +- ); ++ this.destination, BlockPos.containing(lootPos), this.searchRadius, shouldSkipKnownStructures); // Paper - Configurable cartographer treasure maps + if (nearestMapStructure != null) { + ItemStack map = MapItem.create(level, nearestMapStructure.getX(), nearestMapStructure.getZ(), this.zoom, true, true); + MapItem.renderBiomePreviewMap(level, map); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java.patch index 53cc48355e6b..44f3c15cdc3a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java +++ b/net/minecraft/world/level/storage/loot/predicates/ExplosionCondition.java @@ -30,7 +_,8 @@ - if (_float != null) { + if (explosionRadius != null) { RandomSource random = context.getRandom(); - float f = 1.0F / _float; -- return random.nextFloat() <= f; + float probability = 1.0F / explosionRadius; +- return random.nextFloat() <= probability; + // CraftBukkit - <= to < to allow for plugins to completely disable block drops from explosions -+ return random.nextFloat() < f; ++ return random.nextFloat() < probability; } else { return true; } diff --git a/paper-server/patches/sources/net/minecraft/world/scores/PlayerTeam.java.patch b/paper-server/patches/sources/net/minecraft/world/scores/PlayerTeam.java.patch index e2ba03babf12..dc24bbf1dad6 100644 --- a/paper-server/patches/sources/net/minecraft/world/scores/PlayerTeam.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/scores/PlayerTeam.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/scores/PlayerTeam.java +++ b/net/minecraft/world/scores/PlayerTeam.java @@ -222,7 +_,7 @@ - instance -> instance.group( + i -> i.group( Codec.STRING.fieldOf("Name").forGetter(PlayerTeam.Packed::name), ComponentSerialization.CODEC.optionalFieldOf("DisplayName").forGetter(PlayerTeam.Packed::displayName), - ChatFormatting.COLOR_CODEC.optionalFieldOf("TeamColor").forGetter(PlayerTeam.Packed::color), diff --git a/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch b/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch index 24a2d294325d..e6118569b330 100644 --- a/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/scores/Scoreboard.java +++ b/net/minecraft/world/scores/Scoreboard.java -@@ -375,7 +_,7 @@ +@@ -377,7 +_,7 @@ } protected List packPlayerTeams() { @@ -8,4 +8,4 @@ + return this.getPlayerTeams().stream().filter(p -> io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.saveEmptyScoreboardTeams || !p.getPlayers().isEmpty()).map(PlayerTeam::pack).toList(); // Paper - Don't save empty scoreboard teams to scoreboard.dat } - protected void loadPlayerTeam(PlayerTeam.Packed packed) { + protected void loadPlayerTeam(final PlayerTeam.Packed packed) { diff --git a/paper-server/patches/sources/net/minecraft/world/waypoints/WaypointTransmitter.java.patch b/paper-server/patches/sources/net/minecraft/world/waypoints/WaypointTransmitter.java.patch index f276035408d0..a8da863bf0c6 100644 --- a/paper-server/patches/sources/net/minecraft/world/waypoints/WaypointTransmitter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/waypoints/WaypointTransmitter.java.patch @@ -3,8 +3,8 @@ @@ -20,6 +_,7 @@ Waypoint.Icon waypointIcon(); - static boolean doesSourceIgnoreReceiver(LivingEntity entity, ServerPlayer player) { -+ if (!player.getBukkitEntity().canSee(entity.getBukkitEntity())) return true; // Paper - ignore if entity is hidden from player - if (player.isSpectator()) { + static boolean doesSourceIgnoreReceiver(final LivingEntity source, final ServerPlayer receiver) { ++ if (!receiver.getBukkitEntity().canSee(source.getBukkitEntity())) return true; // Paper - ignore if entity is hidden from player + if (receiver.isSpectator()) { return false; - } else if (!entity.isSpectator() && !entity.hasIndirectPassenger(player)) { + } else if (!source.isSpectator() && !source.hasIndirectPassenger(receiver)) { diff --git a/paper-server/patches/sources/net/neoforged/art/internal/RenamerImpl.java.patch b/paper-server/patches/sources/net/neoforged/art/internal/RenamerImpl.java.patch deleted file mode 100644 index 69b4834654c1..000000000000 --- a/paper-server/patches/sources/net/neoforged/art/internal/RenamerImpl.java.patch +++ /dev/null @@ -1,67 +0,0 @@ ---- a/net/neoforged/art/internal/RenamerImpl.java -+++ b/net/neoforged/art/internal/RenamerImpl.java -@@ -35,7 +_,7 @@ - import net.neoforged.cliutils.progress.ProgressReporter; - import org.objectweb.asm.Opcodes; - --class RenamerImpl implements Renamer { -+public class RenamerImpl implements Renamer { // Paper - public - private static final ProgressReporter PROGRESS = ProgressReporter.getDefault(); - static final int MAX_ASM_VERSION = Opcodes.ASM9; - private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; -@@ -75,6 +_,11 @@ - - @Override - public void run(File input, File output) { -+ // Paper start - Add remappingSelf -+ this.run(input, output, false); -+ } -+ public void run(File input, File output, boolean remappingSelf) { -+ // Paper end - if (!this.setup) - this.setup(); - -@@ -105,10 +_,10 @@ - String name = e.getName(); - byte[] data; - try (InputStream entryInput = in.getInputStream(e)) { -- data = readAllBytes(entryInput, e.getSize()); -+ data = entryInput.readAllBytes(); // Paper - Use readAllBytes - } - -- if (name.endsWith(".class")) -+ if (name.endsWith(".class") && !name.contains("META-INF/")) // Paper - Skip META-INF entries - oldEntries.add(ClassEntry.create(name, e.getTime(), data)); - else if (name.equals(MANIFEST_NAME)) - oldEntries.add(ManifestEntry.create(e.getTime(), data)); -@@ -163,15 +_,29 @@ - List newEntries = async.invokeAll(oldEntries, Entry::getName, this::processEntry); - - logger.accept("Adding extras"); -- transformers.forEach(t -> newEntries.addAll(t.getExtras())); -+ // Paper start - I'm pretty sure the duplicates are because the input is already on the classpath -+ List finalNewEntries = newEntries; -+ transformers.forEach(t -> finalNewEntries.addAll(t.getExtras())); - - Set seen = new HashSet<>(); -+ if (remappingSelf) { -+ // deduplicate -+ List n = new ArrayList<>(); -+ for (final Entry e : newEntries) { -+ if (seen.add(e.getName())) { -+ n.add(e); -+ } -+ } -+ newEntries = n; -+ } else { - String dupes = newEntries.stream().map(Entry::getName) - .filter(n -> !seen.add(n)) - .sorted() - .collect(Collectors.joining(", ")); - if (!dupes.isEmpty()) - throw new IllegalStateException("Duplicate entries detected: " + dupes); -+ } -+ // Paper end - - // We care about stable output, so sort, and single thread write. - logger.accept("Sorting"); diff --git a/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarm.java b/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarmland.java similarity index 74% rename from paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarm.java rename to paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarmland.java index 77b3279c9550..cc4f5ef54769 100644 --- a/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarm.java +++ b/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftFarmland.java @@ -1,7 +1,7 @@ package org.bukkit.craftbukkit.block.impl; import io.papermc.paper.annotation.GeneratedClass; -import net.minecraft.world.level.block.FarmBlock; +import net.minecraft.world.level.block.FarmlandBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.IntegerProperty; import org.bukkit.block.data.type.Farmland; @@ -10,10 +10,10 @@ @NullMarked @GeneratedClass -public class CraftFarm extends CraftBlockData implements Farmland { - private static final IntegerProperty MOISTURE = FarmBlock.MOISTURE; +public class CraftFarmland extends CraftBlockData implements Farmland { + private static final IntegerProperty MOISTURE = FarmlandBlock.MOISTURE; - public CraftFarm(BlockState state) { + public CraftFarmland(BlockState state) { super(state); } diff --git a/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowyDirt.java b/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowy.java similarity index 71% rename from paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowyDirt.java rename to paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowy.java index de4248db7661..b839b91d69a2 100644 --- a/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowyDirt.java +++ b/paper-server/src/generated/java/org/bukkit/craftbukkit/block/impl/CraftSnowy.java @@ -1,7 +1,7 @@ package org.bukkit.craftbukkit.block.impl; import io.papermc.paper.annotation.GeneratedClass; -import net.minecraft.world.level.block.SnowyDirtBlock; +import net.minecraft.world.level.block.SnowyBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; import org.bukkit.block.data.Snowable; @@ -10,10 +10,10 @@ @NullMarked @GeneratedClass -public class CraftSnowyDirt extends CraftBlockData implements Snowable { - private static final BooleanProperty SNOWY = SnowyDirtBlock.SNOWY; +public class CraftSnowy extends CraftBlockData implements Snowable { + private static final BooleanProperty SNOWY = SnowyBlock.SNOWY; - public CraftSnowyDirt(BlockState state) { + public CraftSnowy(BlockState state) { super(state); } diff --git a/paper-server/src/main/java/ca/spottedleaf/moonrise/common/util/CoordinateUtils.java b/paper-server/src/main/java/ca/spottedleaf/moonrise/common/util/CoordinateUtils.java index bb5b9c9cb0c7..47d2f0cd0161 100644 --- a/paper-server/src/main/java/ca/spottedleaf/moonrise/common/util/CoordinateUtils.java +++ b/paper-server/src/main/java/ca/spottedleaf/moonrise/common/util/CoordinateUtils.java @@ -17,11 +17,11 @@ public static long getChunkKey(final BlockPos pos) { public static long getChunkKey(final Entity entity) { final ChunkPos pos = entity.chunkPosition(); - return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL); + return ((long)pos.z() << 32) | (pos.x() & 0xFFFFFFFFL); } public static long getChunkKey(final ChunkPos pos) { - return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL); + return ((long)pos.z() << 32) | (pos.x() & 0xFFFFFFFFL); } public static long getChunkKey(final SectionPos pos) { @@ -71,9 +71,9 @@ public static long getChunkSectionKey(final SectionPos pos) { } public static long getChunkSectionKey(final ChunkPos pos, final int y) { - return ((pos.x & SECTION_X_MASK) << SECTION_X_SHIFT) + return ((pos.x() & SECTION_X_MASK) << SECTION_X_SHIFT) | ((y & SECTION_Y_MASK) << SECTION_Y_SHIFT) - | ((pos.z & SECTION_Z_MASK) << SECTION_Z_SHIFT); + | ((pos.z() & SECTION_Z_MASK) << SECTION_Z_SHIFT); } public static long getChunkSectionKey(final BlockPos pos) { diff --git a/paper-server/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/paper-server/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java index c8583cb0bc5a..b3c7107689f0 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java @@ -3,7 +3,6 @@ import com.destroystokyo.paper.entity.RangedEntity; import com.google.common.base.CaseFormat; import io.papermc.paper.entity.SchoolableFish; -import io.papermc.paper.util.ObfHelper; import it.unimi.dsi.fastutil.ints.Int2BooleanFunction; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; @@ -249,9 +248,6 @@ public static GoalKey getKey(Class goalClass) Class type = getGenericType(goalClass); String name = goalClass.getName(); - if (io.papermc.paper.util.MappingEnvironment.reobf()) { - name = ObfHelper.INSTANCE.deobfClassName(name); - } Class holderClass = getTopLevelClass(goalClass); name = getPathName(type, holderClass, name); diff --git a/paper-server/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/paper-server/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java index 605a4a83d0a0..252378f766ca 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java @@ -50,7 +50,7 @@ public static void logSyncLoad(final Level world, final int chunkX, final int ch ++valueInMap.times; - valueInMap.coordinateTimes.compute(ChunkPos.asLong(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> { + valueInMap.coordinateTimes.compute(ChunkPos.pack(chunkX, chunkZ), (Long keyInMap1, Integer valueInMap1) -> { return valueInMap1 == null ? Integer.valueOf(1) : Integer.valueOf(valueInMap1.intValue() + 1); }); @@ -103,8 +103,7 @@ public static JsonObject serialize() { for (Long2IntMap.Entry coordinate : pair.getSecond().coordinateTimes.long2IntEntrySet()) { final long key = coordinate.getLongKey(); final int times = coordinate.getIntValue(); - final ChunkPos chunkPos = new ChunkPos(key); - coordinates.add("(" + chunkPos.x + "," + chunkPos.z + "): " + times); + coordinates.add("(" + ChunkPos.getX(key) + "," + ChunkPos.getZ(key) + "): " + times); } stacktrace.add("coordinates", coordinates); diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java index 0d2fcedf15a9..025fe74877c3 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java @@ -7,26 +7,26 @@ public class PaperNetworkClient implements NetworkClient { - private final Connection networkManager; + private final Connection connection; - PaperNetworkClient(Connection networkManager) { - this.networkManager = networkManager; + PaperNetworkClient(Connection connection) { + this.connection = connection; } @Override public InetSocketAddress getAddress() { - return (InetSocketAddress) this.networkManager.getRemoteAddress(); + return (InetSocketAddress) this.connection.getRemoteAddress(); } @Override public int getProtocolVersion() { - return this.networkManager.protocolVersion; + return this.connection.protocolVersion; } @Nullable @Override public InetSocketAddress getVirtualHost() { - return this.networkManager.virtualHost; + return this.connection.virtualHost; } public static InetSocketAddress prepareVirtualHost(String host, int port) { diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java index d926ad804355..931211b57134 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java @@ -4,8 +4,8 @@ class PaperStatusClient extends PaperNetworkClient implements StatusClient { - PaperStatusClient(Connection networkManager) { - super(networkManager); + PaperStatusClient(Connection connection) { + super(connection); } } diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java index b40b79beb311..5e89bad7231d 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java @@ -20,8 +20,8 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP private List originalSample; - private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) { - super(server, new PaperStatusClient(networkManager), ping.version().map(ServerStatus.Version::protocol).orElse(-1), server.server.getServerIcon()); + private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection connection, ServerStatus ping) { + super(server, new PaperStatusClient(connection), ping.version().map(ServerStatus.Version::protocol).orElse(-1), server.server.getServerIcon()); this.originalSample = ping.players().map(ServerStatus.Players::sample).orElse(null); // GH-1473 - pre-tick race condition NPE } @@ -63,13 +63,13 @@ private List getPlayerSampleHandle() { return profiles; } - public static void processRequest(MinecraftServer server, Connection networkManager) { - StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus()); + public static void processRequest(MinecraftServer server, Connection connection) { + StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, connection, server.getStatus()); server.server.getPluginManager().callEvent(event); // Close connection immediately if event is cancelled if (event.isCancelled()) { - networkManager.disconnect((Component) null); + connection.disconnect((Component) null); return; } @@ -99,7 +99,7 @@ public static void processRequest(MinecraftServer server, Connection networkMana final ServerStatus ping = new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile()); // Send response - networkManager.send(new ClientboundStatusResponsePacket(ping)); + connection.send(new ClientboundStatusResponsePacket(ping)); } } diff --git a/paper-server/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java b/paper-server/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java index b4ce727bd292..6d986b9f3b8b 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java @@ -9,6 +9,7 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import io.papermc.paper.profile.MutablePropertyMap; +import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Util; import net.minecraft.core.UUIDUtil; import net.minecraft.server.MinecraftServer; @@ -77,7 +78,7 @@ public void setProperty(ProfileProperty property) { PropertyMap properties = profile.properties(); properties.removeAll(name); - Preconditions.checkArgument(properties.size() < 16, "Cannot add more than 16 properties to a profile"); + Preconditions.checkArgument(properties.size() < ExtraCodecs.MAX_PROPERTIES, "Cannot add more than %s properties to a profile", ExtraCodecs.MAX_PROPERTIES); properties.put(name, new Property(name, property.getValue(), property.getSignature())); } @@ -406,7 +407,7 @@ public int hashCode() { public String toString() { return "CraftPlayerProfile [uniqueId=" + getId() + ", name=" + getName() + - ", properties=" + org.bukkit.craftbukkit.profile.CraftPlayerProfile.toString(this.profile.properties()) + + ", properties=" + this.profile.properties() + "]"; } diff --git a/paper-server/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java b/paper-server/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java index a2c575e9409f..be63ac91a953 100644 --- a/paper-server/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java +++ b/paper-server/src/main/java/io/papermc/paper/advancement/PaperAdvancementDisplay.java @@ -31,7 +31,7 @@ public record PaperAdvancementDisplay(DisplayInfo handle) implements Advancement @Override public @NotNull ItemStack icon() { - return CraftItemStack.asBukkitCopy(this.handle.getIcon()); + return CraftItemStack.asBukkitCopy(this.handle.getIcon().create()); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java b/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java index e6a4d4b958bc..3d5ade4c9892 100644 --- a/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java +++ b/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java @@ -7,6 +7,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.JavaOps; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import io.papermc.paper.dialog.Dialog; @@ -47,7 +48,7 @@ import net.kyori.adventure.text.object.PlayerHeadObjectContents; import net.kyori.adventure.text.object.SpriteObjectContents; import net.kyori.adventure.util.Index; -import net.minecraft.commands.arguments.selector.SelectorPattern; +import net.minecraft.commands.arguments.selector.EntitySelector; import net.minecraft.core.UUIDUtil; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; @@ -59,10 +60,11 @@ import net.minecraft.network.chat.contents.TranslatableContents; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.CompilableString; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.StringRepresentable; import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemStackTemplate; import net.minecraft.world.item.component.ResolvableProfile; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -195,13 +197,12 @@ public String getSerializedName() { ).apply(instance, (key, uuid, component) -> HoverEvent.showEntity(key, uuid, component.orElse(null)))); public static final MapCodec> SHOW_ITEM_CODEC = net.minecraft.network.chat.HoverEvent.ShowItem.CODEC.xmap(internal -> { - @Subst("key") final String typeKey = internal.item().getItemHolder().unwrapKey().orElseThrow().identifier().toString(); - return HoverEvent.showItem(Key.key(typeKey), internal.item().getCount(), PaperAdventure.asAdventure(internal.item().getComponentsPatch())); + @Subst("key") final String typeKey = internal.item().typeHolder().unwrapKey().orElseThrow().identifier().toString(); + return HoverEvent.showItem(Key.key(typeKey), internal.item().count(), PaperAdventure.asAdventure(internal.item().components())); }, adventure -> { final Item itemType = BuiltInRegistries.ITEM.getValue(PaperAdventure.asVanilla(adventure.value().item())); final Map dataComponentsMap = adventure.value().dataComponents(); - final ItemStack stack = new ItemStack(BuiltInRegistries.ITEM.wrapAsHolder(itemType), adventure.value().count(), PaperAdventure.asVanilla(dataComponentsMap)); - return new net.minecraft.network.chat.HoverEvent.ShowItem(stack); + return new net.minecraft.network.chat.HoverEvent.ShowItem(new ItemStackTemplate(BuiltInRegistries.ITEM.wrapAsHolder(itemType), adventure.value().count(), PaperAdventure.asVanilla(dataComponentsMap))); }); static final HoverEventType SHOW_ENTITY_HOVER_EVENT_TYPE = new HoverEventType<>(SHOW_ENTITY_CODEC, "show_entity"); @@ -396,9 +397,9 @@ static Function> nullableGetter(final Function SCORE_COMPONENT_INNER_MAP_CODEC = ScoreContents.INNER_CODEC.xmap( - s -> Component.score(s.name().map(SelectorPattern::pattern, identity()), s.objective()), - s -> new ScoreContents(SelectorPattern.parse(s.name()).>map(Either::left).result().orElse(Either.right(s.name())), s.objective()) - ); // TODO we might want to ask adventure for a nice way we can avoid parsing and flattening the SelectorPattern on every conversion. + s -> Component.score(s.name().map(CompilableString::source, identity()), s.objective()), + s -> new ScoreContents(EntitySelector.COMPILABLE_CODEC.parse(JavaOps.INSTANCE, s.name())., String>>map(Either::left).result().orElse(Either.right(s.name())), s.objective()) + ); // TODO we might want to ask adventure for a nice way we can avoid parsing and flattening the selector string on every conversion. static final MapCodec SCORE_COMPONENT_MAP_CODEC = SCORE_COMPONENT_INNER_MAP_CODEC.fieldOf("score"); static final MapCodec SELECTOR_COMPONENT_MAP_CODEC = mapCodec((instance) -> { return instance.group( diff --git a/paper-server/src/main/java/io/papermc/paper/adventure/BossBarImplementationImpl.java b/paper-server/src/main/java/io/papermc/paper/adventure/BossBarImplementationImpl.java index 23bd6d2d8fed..4d5f001b2eeb 100644 --- a/paper-server/src/main/java/io/papermc/paper/adventure/BossBarImplementationImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/adventure/BossBarImplementationImpl.java @@ -27,6 +27,7 @@ public BossBarImplementationImpl(final BossBar bar) { public void playerShow(final CraftPlayer player) { if (this.vanilla == null) { this.vanilla = new ServerBossEvent( + net.minecraft.util.Mth.createInsecureUUID(net.minecraft.util.RandomSource.create()), PaperAdventure.asVanilla(this.bar.name()), PaperAdventure.asVanilla(this.bar.color()), PaperAdventure.asVanilla(this.bar.overlay()) diff --git a/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java index 8cd1ea370dd4..d0f87ef856d9 100644 --- a/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +++ b/paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java @@ -47,6 +47,7 @@ import net.minecraft.nbt.Tag; import net.minecraft.nbt.TagParser; import net.minecraft.network.chat.ComponentUtils; +import net.minecraft.network.chat.ResolutionContext; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; @@ -264,7 +265,8 @@ public static Component resolveWithContext(final @NotNull Component component, f css.bypassSelectorPermissions = true; } try { - return asAdventure(ComponentUtils.updateForEntity(css, asVanilla(component), scoreboardSubject == null ? null : ((CraftEntity) scoreboardSubject).getHandle(), 0)); + final ResolutionContext resoutionContext = ResolutionContext.builder().withSource(css).withEntityOverride(scoreboardSubject == null ? null : ((CraftEntity) scoreboardSubject).getHandle()).build(); + return asAdventure(ComponentUtils.resolve(resoutionContext, asVanilla(component), 0)); } catch (final CommandSyntaxException e) { throw new IOException(e); } finally { diff --git a/paper-server/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java b/paper-server/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java index b03b2d098c20..582937bbb8b5 100644 --- a/paper-server/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java +++ b/paper-server/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java @@ -193,8 +193,8 @@ public void modifyBlocks(ClientboundLevelChunkWithLightPacket chunkPacket, Chunk } LevelChunk chunk = chunkPacketInfo.getChunk(); - int x = chunk.getPos().x; - int z = chunk.getPos().z; + int x = chunk.getPos().x(); + int z = chunk.getPos().z(); Level level = chunk.getLevel(); ((ChunkPacketInfoAntiXray) chunkPacketInfo).setNearbyChunks(level.getChunkIfLoaded(x - 1, z), level.getChunkIfLoaded(x + 1, z), level.getChunkIfLoaded(x, z - 1), level.getChunkIfLoaded(x, z + 1)); executor.execute((Runnable) chunkPacketInfo); diff --git a/paper-server/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java b/paper-server/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java index bff395667f69..a825c1217e62 100644 --- a/paper-server/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/command/brigadier/argument/VanillaArgumentProviderImpl.java @@ -250,7 +250,7 @@ protected Set delegate() { return this.wrap(SwizzleArgument.swizzle(), (result) -> { final EnumSet bukkitAxes = EnumSet.noneOf(Axis.class); for (final Direction.Axis nmsAxis : result) { - bukkitAxes.add(CraftBlockData.toBukkit(nmsAxis, Axis.class)); + bukkitAxes.add(CraftBlockData.fromVanilla(nmsAxis, Axis.class)); } return new AxisSetImpl(bukkitAxes); }); @@ -270,7 +270,7 @@ public ArgumentType blockState() { @Override public ArgumentType itemStack() { return this.wrap(ItemArgument.item(PaperCommands.INSTANCE.getBuildContext()), (result) -> { - return CraftItemStack.asBukkitCopy(result.createItemStack(1, true)); + return CraftItemStack.asBukkitCopy(result.createItemStack(1)); }); } diff --git a/paper-server/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java b/paper-server/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java index 4c3d5712c677..dc84b7c3746f 100644 --- a/paper-server/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java +++ b/paper-server/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java @@ -15,13 +15,10 @@ import net.kyori.adventure.text.ComponentLike; import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.TextComponent; -import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponentType; -import net.minecraft.core.component.TypedDataComponent; -import net.minecraft.core.registries.Registries; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.SnbtPrinterTagVisitor; @@ -29,13 +26,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.world.item.ItemStack; import org.bukkit.command.CommandSender; -import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; +import static java.util.Objects.requireNonNull; import static net.kyori.adventure.text.Component.join; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.textOfChildren; @@ -56,71 +53,77 @@ public boolean execute(final CommandSender sender, final String subCommand, fina return true; } - @SuppressWarnings({"unchecked", "OptionalAssignedToNull", "rawtypes"}) + @SuppressWarnings({"unchecked", "rawtypes"}) private void doDumpItem(final CommandSender sender, final boolean includeAllComponents) { if (!(sender instanceof final Player player)) { sender.sendMessage("Only players can use this command"); return; } - final ItemStack itemStack = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand()); - final TextComponent.Builder visualOutput = Component.text(); - final StringBuilder itemCommandBuilder = new StringBuilder(); - final String itemName = itemStack.getItemHolder().unwrapKey().orElseThrow().identifier().toString(); - itemCommandBuilder.append(itemName); - visualOutput.append(text(itemName, YELLOW)); // item type - final Set> referencedComponentTypes = Collections.newSetFromMap(new IdentityHashMap<>()); - final DataComponentPatch patch = itemStack.getComponentsPatch(); - referencedComponentTypes.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList()); - final DataComponentMap prototype = itemStack.getItem().components(); + final TextComponent.Builder output = Component.text(); + final StringBuilder itemToCopy = new StringBuilder(); + final ItemStack item = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand()); + final String itemName = item.typeHolder().unwrapKey().orElseThrow().identifier().toString(); + itemToCopy.append(itemName); + output.append(text(itemName, YELLOW)); // item type + + final Set> remainingComponents = Collections.newSetFromMap(new IdentityHashMap<>()); + final DataComponentPatch patch = item.getComponentsPatch(); + remainingComponents.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList()); + final DataComponentMap prototype = item.getPrototype(); if (includeAllComponents) { - referencedComponentTypes.addAll(prototype.keySet()); + remainingComponents.addAll(prototype.keySet()); } + remainingComponents.removeIf(DataComponentType::isTransient); - final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess(); - final RegistryOps ops = access.createSerializationContext(NbtOps.INSTANCE); - final Registry> registry = access.lookupOrThrow(Registries.DATA_COMPONENT_TYPE); - final List componentComponents = new ArrayList<>(); - final List commandComponents = new ArrayList<>(); - for (final DataComponentType type : referencedComponentTypes) { - final String path = registry.getResourceKey(type).orElseThrow().identifier().getPath(); - final @Nullable Optional patchedValue = patch.get(type); - final @Nullable TypedDataComponent prototypeValue = prototype.getTyped(type); - if (patchedValue != null) { + final RegistryOps ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); + final List writtenComponents = new ArrayList<>(); + final List componentsToCopy = new ArrayList<>(); + for (final Map.Entry, Optional> entry : patch.entrySet()) { // patch + final DataComponentType type = entry.getKey(); + if (remainingComponents.remove(type)) { + final String path = requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(type)).getPath(); + final Optional patchedValue = entry.getValue(); if (patchedValue.isEmpty()) { - componentComponents.add(text().append(text('!', RED), text(path, AQUA))); - commandComponents.add("!" + path); + writtenComponents.add(text().append(text('!', RED), text(path, AQUA))); + componentsToCopy.add("!" + path); } else { final Tag serialized = (Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, patchedValue.get()).getOrThrow(); - writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); + writeComponentValue(writtenComponents::add, componentsToCopy::add, path, serialized); } - } else if (includeAllComponents && prototypeValue != null) { - final Tag serialized = prototypeValue.encodeValue(ops).getOrThrow(); - writeComponentValue(componentComponents::add, commandComponents::add, path, serialized); } } - if (!componentComponents.isEmpty()) { - visualOutput.append( + + if (includeAllComponents) { + for (final DataComponentType type : remainingComponents) { // prototype + final String path = requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(type)).getPath(); + final Tag serialized = requireNonNull(prototype.getTyped(type)).encodeValue(ops).getOrThrow(); + writeComponentValue(writtenComponents::add, componentsToCopy::add, path, serialized); + } + } + + if (!writtenComponents.isEmpty()) { + output.append( text("[", color(0x8910CE)), - join(JoinConfiguration.separator(text(",", GRAY)), componentComponents), + join(JoinConfiguration.separator(text(",", GRAY)), writtenComponents), text("]", color(0x8910CE)) ); - itemCommandBuilder + itemToCopy .append("[") - .append(String.join(",", commandComponents)) + .append(String.join(",", componentsToCopy)) .append("]"); } - player.sendMessage(visualOutput.build().compact()); + player.sendMessage(output.build().compact()); final Component copyMsg = text("Click to copy item definition to clipboard for use with /give", GRAY, ITALIC); - sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemCommandBuilder.toString()))); + sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemToCopy.toString()))); } - private static void writeComponentValue(final Consumer visualOutput, final Consumer commandOutput, final String path, final Tag serialized) { - visualOutput.accept(textOfChildren( + private static void writeComponentValue(final Consumer output, final Consumer copyOutput, final String path, final Tag serialized) { + output.accept(textOfChildren( text(path, color(0xFF7FD7)), text("=", WHITE), PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized)) )); - commandOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized)); + copyOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized)); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java index e3e21acb82b5..c5ae414cdf4e 100644 --- a/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +++ b/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java @@ -125,9 +125,9 @@ private void listEntities(final CommandSender sender, final String[] args) { info.getRight().entrySet().stream() .sorted((a, b) -> !a.getValue().equals(b.getValue()) ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString())) .limit(10).forEach(e -> { - final int x = (e.getKey().x << 4) + 8; - final int z = (e.getKey().z << 4) + 8; - final Component message = text(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")) + final int x = (e.getKey().x() << 4) + 8; + final int z = (e.getKey().z() << 4) + 8; + final Component message = text(" " + e.getValue() + ": " + e.getKey().x() + ", " + e.getKey().z() + (chunkProviderServer.isPositionTicking(e.getKey().pack()) ? " (Ticking)" : " (Non-Ticking)")) .hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN))) .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z)); sender.sendMessage(message); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java index 3dd96af2ffea..52195607af4c 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java @@ -73,7 +73,7 @@ public final class ServerboundPacketClassSerializer extends ScalarSerializer retrieveCookie(final NamespacedKey key) { Preconditions.checkArgument(key != null, "Cookie key cannot be null"); CompletableFuture future = new CompletableFuture<>(); - Identifier resourceLocation = CraftNamespacedKey.toMinecraft(key); - this.requestedCookies.put(resourceLocation, new CookieFuture(resourceLocation, future)); + Identifier id = CraftNamespacedKey.toMinecraft(key); + this.requestedCookies.put(id, new CookieFuture(id, future)); - this.connection.send(new ClientboundCookieRequestPacket(resourceLocation)); + this.connection.send(new ClientboundCookieRequestPacket(id)); return future; } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java index f6783d5f9279..08f828359b98 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java @@ -46,24 +46,29 @@ import io.papermc.paper.datacomponent.item.PaperWritableBookContent; import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.keys.BannerPatternKeys; +import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.set.RegistryKeySet; import java.util.HashMap; import java.util.Map; import java.util.function.Function; +import net.minecraft.core.HolderSet; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.util.Unit; -import net.minecraft.world.item.EitherHolder; import net.minecraft.world.item.Rarity; import net.minecraft.world.item.component.InstrumentComponent; import net.minecraft.world.item.component.MapPostProcessing; -import net.minecraft.world.item.component.ProvidesTrimMaterial; +import net.minecraft.world.level.block.entity.BannerPattern; import org.bukkit.DyeColor; +import org.bukkit.block.banner.PatternType; import org.bukkit.craftbukkit.CraftArt; import org.bukkit.craftbukkit.CraftMusicInstrument; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.damage.CraftDamageType; import org.bukkit.craftbukkit.entity.CraftCat; import org.bukkit.craftbukkit.entity.CraftChicken; @@ -109,7 +114,7 @@ public static void bootstrap() { registerIdentity(DataComponents.POTION_DURATION_SCALE); register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE); - register(DataComponents.DAMAGE_TYPE, nms -> CraftDamageType.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftDamageType.bukkitToMinecraftHolder(api))); + register(DataComponents.DAMAGE_TYPE, CraftDamageType::minecraftHolderToBukkit, CraftDamageType::bukkitToMinecraftHolder); register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla); register(DataComponents.LORE, PaperItemLore::new); @@ -136,6 +141,7 @@ public static void bootstrap() { register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new); register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new); + register(DataComponents.DYE, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); register(DataComponents.DYED_COLOR, PaperDyedItemColor::new); register(DataComponents.MAP_COLOR, PaperMapItemColor::new); register(DataComponents.MAP_ID, PaperMapId::new); @@ -152,11 +158,11 @@ public static void bootstrap() { // entity data // bucket entity data // block entity data - register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); - register(DataComponents.PROVIDES_TRIM_MATERIAL, nms -> CraftTrimMaterial.minecraftHolderToBukkit(nms.material().unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new ProvidesTrimMaterial(CraftTrimMaterial.bukkitToMinecraftHolder(api))); + register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api))); + register(DataComponents.PROVIDES_TRIM_MATERIAL, CraftTrimMaterial::minecraftHolderToBukkit, CraftTrimMaterial::bukkitToMinecraftHolder); register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new); register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new); - register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms); + register(DataComponents.PROVIDES_BANNER_PATTERNS, set -> PaperRegistrySets.convertToApi(RegistryKey.BANNER_PATTERN, set), set -> PaperRegistrySets.convertToNms(Registries.BANNER_PATTERN, Conversions.global().lookup(), set)); register( DataComponents.RECIPES, nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey), @@ -183,6 +189,7 @@ public static void bootstrap() { register(DataComponents.KINETIC_WEAPON, PaperKineticWeapon::new); register(DataComponents.ATTACK_RANGE, PaperAttackRange::new); register(DataComponents.SWING_ANIMATION, PaperSwingAnimation::new); + // registerIdentity(DataComponents.ADDITIONAL_TRADE_COST); register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder); register(DataComponents.WOLF_VARIANT, CraftWolf.CraftVariant::minecraftHolderToBukkit, CraftWolf.CraftVariant::bukkitToMinecraftHolder); register(DataComponents.WOLF_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); @@ -196,15 +203,19 @@ public static void bootstrap() { register(DataComponents.MOOSHROOM_VARIANT, nms -> MushroomCow.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.cow.MushroomCow.Variant.values()[api.ordinal()]); register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.byId(api.ordinal())); register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder); + register(DataComponents.PIG_SOUND_VARIANT, CraftPig.CraftSoundVariant::minecraftHolderToBukkit, CraftPig.CraftSoundVariant::bukkitToMinecraftHolder); register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api))); + register(DataComponents.COW_SOUND_VARIANT, CraftCow.CraftSoundVariant::minecraftHolderToBukkit, CraftCow.CraftSoundVariant::bukkitToMinecraftHolder); + register(DataComponents.CHICKEN_VARIANT, CraftChicken.CraftVariant::minecraftHolderToBukkit, CraftChicken.CraftVariant::bukkitToMinecraftHolder); + register(DataComponents.CHICKEN_SOUND_VARIANT, CraftChicken.CraftSoundVariant::minecraftHolderToBukkit, CraftChicken.CraftSoundVariant::bukkitToMinecraftHolder); register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder); - register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, nms -> CraftZombieNautilus.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftZombieNautilus.CraftVariant.bukkitToMinecraftHolder(api))); + register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, CraftZombieNautilus.CraftVariant::minecraftHolderToBukkit, CraftZombieNautilus.CraftVariant::bukkitToMinecraftHolder); register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Variant.byId(api.ordinal())); register(DataComponents.PAINTING_VARIANT, CraftArt::minecraftHolderToBukkit, CraftArt::bukkitToMinecraftHolder); register(DataComponents.LLAMA_VARIANT, nms -> Llama.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Llama.Variant.byId(api.ordinal())); register(DataComponents.AXOLOTL_VARIANT, nms -> Axolotl.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.byId(api.ordinal())); register(DataComponents.CAT_VARIANT, CraftCat.CraftType::minecraftHolderToBukkit, CraftCat.CraftType::bukkitToMinecraftHolder); + register(DataComponents.CAT_SOUND_VARIANT, CraftCat.CraftSoundVariant::minecraftHolderToBukkit, CraftCat.CraftSoundVariant::bukkitToMinecraftHolder); register(DataComponents.CAT_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData())); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java index f8ba50404d24..ff1e61f6ce11 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java @@ -2,11 +2,9 @@ import com.destroystokyo.paper.profile.PlayerProfile; import com.google.common.base.Preconditions; -import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.data.util.Conversions; import io.papermc.paper.registry.set.PaperRegistrySets; import io.papermc.paper.registry.set.RegistryKeySet; -import io.papermc.paper.registry.tag.TagKey; import io.papermc.paper.text.Filtered; import net.kyori.adventure.key.Key; import net.kyori.adventure.util.TriState; @@ -185,7 +183,7 @@ public UseRemainder useRemainder(final ItemStack stack) { Preconditions.checkArgument(stack != null, "Item cannot be null"); Preconditions.checkArgument(!stack.isEmpty(), "Remaining item cannot be empty!"); return new PaperUseRemainder( - new net.minecraft.world.item.component.UseRemainder(CraftItemStack.asNMSCopy(stack)) + new net.minecraft.world.item.component.UseRemainder(net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(stack))) ); } @@ -201,8 +199,8 @@ public UseCooldown.Builder useCooldown(final float seconds) { } @Override - public DamageResistant damageResistant(final TagKey types) { - return new PaperDamageResistant(new net.minecraft.world.item.component.DamageResistant(PaperRegistries.toNms(types))); + public DamageResistant damageResistant(final RegistryKeySet types) { + return new PaperDamageResistant(new net.minecraft.world.item.component.DamageResistant(PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, Conversions.global().lookup(), types))); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperAttackRange.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperAttackRange.java index f721973602bf..6120ca6216e2 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperAttackRange.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperAttackRange.java @@ -14,22 +14,22 @@ public net.minecraft.world.item.component.AttackRange getHandle() { @Override public float minReach() { - return this.impl.minRange(); + return this.impl.minReach(); } @Override public float maxReach() { - return this.impl.maxRange(); + return this.impl.maxReach(); } @Override public float minCreativeReach() { - return this.impl.minCreativeRange(); + return this.impl.minCreativeReach(); } @Override public float maxCreativeReach() { - return this.impl.maxCreativeRange(); + return this.impl.maxCreativeReach(); } @Override @@ -44,10 +44,10 @@ public float mobFactor() { static final class BuilderImpl implements AttackRange.Builder { - private float minReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.minRange(); - private float maxReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.maxRange(); - private float minCreativeReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.minCreativeRange(); - private float maxCreativeReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.maxCreativeRange(); + private float minReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.minReach(); + private float maxReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.maxReach(); + private float minCreativeReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.minCreativeReach(); + private float maxCreativeReach = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.maxCreativeReach(); private float hitboxMargin = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.hitboxMargin(); private float mobFactor = net.minecraft.world.item.component.AttackRange.CODEC_DEFAULT.mobFactor(); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlockItemDataProperties.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlockItemDataProperties.java index 5757e16c5948..9968838b8818 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlockItemDataProperties.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlockItemDataProperties.java @@ -19,13 +19,13 @@ public record PaperBlockItemDataProperties( public BlockData createBlockData(final BlockType blockType) { final Block block = CraftBlockType.bukkitToMinecraftNew(blockType); final BlockState defaultState = block.defaultBlockState(); - return this.impl.apply(defaultState).createCraftBlockData(); + return this.impl.apply(defaultState).asBlockData(); } @Override public BlockData applyTo(final BlockData blockData) { final BlockState state = ((CraftBlockData) blockData).getState(); - return this.impl.apply(state).createCraftBlockData(); + return this.impl.apply(state).asBlockData(); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlocksAttacks.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlocksAttacks.java index 71c927abdebc..651d95394fd7 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlocksAttacks.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBlocksAttacks.java @@ -6,12 +6,15 @@ import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction; import io.papermc.paper.datacomponent.item.blocksattacks.PaperDamageReduction; import io.papermc.paper.datacomponent.item.blocksattacks.PaperItemDamageFunction; -import io.papermc.paper.registry.PaperRegistries; -import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.set.RegistryKeySet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import java.util.Optional; import net.kyori.adventure.key.Key; +import net.minecraft.core.registries.Registries; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.damage.DamageType; import org.jspecify.annotations.Nullable; @@ -46,9 +49,8 @@ public ItemDamageFunction itemDamage() { } @Override - public @Nullable TagKey bypassedBy() { - final Optional> tagKey = this.impl.bypassedBy().map(PaperRegistries::fromNms); - return tagKey.orElse(null); + public @Nullable RegistryKeySet bypassedBy() { + return this.impl.bypassedBy().map(holders -> PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, holders)).orElse(null); } @Override @@ -67,7 +69,7 @@ static final class BuilderImpl implements Builder { private float disableCooldownScale = 1.0F; private List damageReductions = new ObjectArrayList<>(); private ItemDamageFunction itemDamage = new PaperItemDamageFunction(net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT); - private @Nullable TagKey bypassedBy; + private @Nullable RegistryKeySet bypassedBy; private @Nullable Key blockSound; private @Nullable Key disableSound; @@ -104,7 +106,7 @@ public Builder itemDamage(final ItemDamageFunction function) { } @Override - public Builder bypassedBy(@Nullable final TagKey bypassedBy) { + public Builder bypassedBy(final @Nullable RegistryKeySet bypassedBy) { this.bypassedBy = bypassedBy; return this; } @@ -128,7 +130,7 @@ public BlocksAttacks build() { this.disableCooldownScale, this.damageReductions.stream().map(damageReduction -> ((PaperDamageReduction) damageReduction).internal()).toList(), ((PaperItemDamageFunction) this.itemDamage).internal(), - Optional.ofNullable(this.bypassedBy).map(PaperRegistries::toNms), + Optional.ofNullable(this.bypassedBy).map(holders -> PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, Conversions.global().lookup(), holders)), Optional.ofNullable(this.blockSound).map(PaperAdventure::resolveSound), Optional.ofNullable(this.disableSound).map(PaperAdventure::resolveSound) )); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBundleContents.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBundleContents.java index ba95ce77dbdd..e36230cfbc28 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBundleContents.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperBundleContents.java @@ -1,7 +1,6 @@ package io.papermc.paper.datacomponent.item; import com.google.common.base.Preconditions; -import io.papermc.paper.util.MCUtil; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.List; import org.bukkit.craftbukkit.inventory.CraftItemStack; @@ -19,18 +18,18 @@ public net.minecraft.world.item.component.BundleContents getHandle() { @Override public List contents() { - return MCUtil.transformUnmodifiable((List) this.impl.items(), CraftItemStack::asBukkitCopy); + return this.impl.itemCopyStream().map(CraftItemStack::asBukkitCopy).toList(); } static final class BuilderImpl implements BundleContents.Builder { - private final List items = new ObjectArrayList<>(); + private final List items = new ObjectArrayList<>(); @Override public BundleContents.Builder add(final ItemStack stack) { Preconditions.checkArgument(stack != null, "stack cannot be null"); Preconditions.checkArgument(!stack.isEmpty(), "stack cannot be empty"); - this.items.add(CraftItemStack.asNMSCopy(stack)); + this.items.add(net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(stack))); return this; } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperChargedProjectiles.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperChargedProjectiles.java index 2129dd67fd02..3972d8097e13 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperChargedProjectiles.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperChargedProjectiles.java @@ -19,7 +19,7 @@ public net.minecraft.world.item.component.ChargedProjectiles getHandle() { @Override public List projectiles() { - return MCUtil.transformUnmodifiable(this.impl.getItems() /*makes copies internally*/, CraftItemStack::asCraftMirror); + return MCUtil.transformUnmodifiable(this.impl.itemCopies() /*makes copies internally*/, CraftItemStack::asCraftMirror); } static final class BuilderImpl implements ChargedProjectiles.Builder { @@ -45,7 +45,7 @@ public ChargedProjectiles build() { if (this.items.isEmpty()) { return new PaperChargedProjectiles(net.minecraft.world.item.component.ChargedProjectiles.EMPTY); } - return new PaperChargedProjectiles(net.minecraft.world.item.component.ChargedProjectiles.of(this.items)); + return new PaperChargedProjectiles(net.minecraft.world.item.component.ChargedProjectiles.ofNonEmpty(this.items)); } } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java index adc986c8b3d6..8f828e204bde 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java @@ -1,7 +1,8 @@ package io.papermc.paper.datacomponent.item; -import io.papermc.paper.registry.PaperRegistries; -import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.set.RegistryKeySet; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.damage.DamageType; @@ -15,7 +16,7 @@ public net.minecraft.world.item.component.DamageResistant getHandle() { } @Override - public TagKey types() { - return PaperRegistries.fromNms(this.impl.types()); + public RegistryKeySet types() { + return PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, this.impl.types()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemContainerContents.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemContainerContents.java index fe86d636f6e1..f627534af3f7 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemContainerContents.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemContainerContents.java @@ -19,7 +19,7 @@ public net.minecraft.world.item.component.ItemContainerContents getHandle() { @Override public List contents() { - return MCUtil.transformUnmodifiable(this.impl.items, CraftItemStack::asBukkitCopy); + return MCUtil.transformUnmodifiable(this.impl.items, optional -> optional.map(net.minecraft.world.item.ItemStackTemplate::create).map(CraftItemStack::asBukkitCopy).orElse(null)); } static final class BuilderImpl implements ItemContainerContents.Builder { diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperJukeboxPlayable.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperJukeboxPlayable.java index b80f1420703e..7c8fc2934307 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperJukeboxPlayable.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperJukeboxPlayable.java @@ -1,9 +1,7 @@ package io.papermc.paper.datacomponent.item; -import net.minecraft.world.item.EitherHolder; import org.bukkit.JukeboxSong; import org.bukkit.craftbukkit.CraftJukeboxSong; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.util.Handleable; public record PaperJukeboxPlayable( @@ -17,10 +15,7 @@ public net.minecraft.world.item.JukeboxPlayable getHandle() { @Override public JukeboxSong jukeboxSong() { - return this.impl.song() - .unwrap(CraftRegistry.getMinecraftRegistry()) - .map(CraftJukeboxSong::minecraftHolderToBukkit) - .orElseThrow(); + return CraftJukeboxSong.minecraftHolderToBukkit(this.impl.song()); } static final class BuilderImpl implements JukeboxPlayable.Builder { @@ -40,7 +35,7 @@ public JukeboxPlayable.Builder jukeboxSong(final JukeboxSong song) { @Override public JukeboxPlayable build() { return new PaperJukeboxPlayable(new net.minecraft.world.item.JukeboxPlayable( - new EitherHolder<>(CraftJukeboxSong.bukkitToMinecraftHolder(this.song)) + CraftJukeboxSong.bukkitToMinecraftHolder(this.song) )); } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java index 6a88eeda16e4..ecafbf6ea8b2 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java @@ -21,6 +21,7 @@ import net.kyori.adventure.text.object.PlayerHeadObjectContents; import net.minecraft.core.ClientAsset; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ExtraCodecs; import net.minecraft.util.StringUtil; import net.minecraft.world.entity.player.PlayerModelType; import net.minecraft.world.entity.player.PlayerSkin; @@ -196,7 +197,7 @@ public ResolvableProfile.Builder addProperty(final ProfileProperty property) { final Property newProperty = new Property(property.getName(), property.getValue(), property.getSignature()); if (!this.propertyMap.containsEntry(property.getName(), newProperty)) { // underlying map is a multimap that doesn't allow duplicate key-value pair final int newSize = this.propertyMap.size() + 1; - Preconditions.checkArgument(newSize <= 16, "Cannot have more than 16 properties, was %s", newSize); + Preconditions.checkArgument(newSize <= ExtraCodecs.MAX_PROPERTIES, "Cannot have more than %s properties, was %s", ExtraCodecs.MAX_PROPERTIES, newSize); } this.propertyMap.put(property.getName(), newProperty); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java index c2c045069407..c919b6cf35dc 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java @@ -15,6 +15,6 @@ public net.minecraft.world.item.component.UseRemainder getHandle() { @Override public ItemStack transformInto() { - return CraftItemStack.asBukkitCopy(this.impl.convertInto()); + return CraftItemStack.asBukkitCopy(this.impl.convertInto().create()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java b/paper-server/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java index 3200aef1ba5d..5741a60faba7 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java @@ -7,14 +7,11 @@ import io.papermc.paper.plugin.provider.PluginProvider; import io.papermc.paper.plugin.provider.type.paper.PaperPluginParent; import io.papermc.paper.plugin.provider.type.spigot.SpigotPluginProvider; -import io.papermc.paper.pluginremap.PluginRemapper; import java.util.Set; import java.util.TreeSet; -import java.util.function.Function; import joptsimple.OptionSet; import net.minecraft.server.dedicated.DedicatedServer; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.java.LibraryLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -30,15 +27,10 @@ public class PluginInitializerManager { private static PluginInitializerManager impl; private final Path pluginDirectory; private final Path updateDirectory; - public final io.papermc.paper.pluginremap.@org.checkerframework.checker.nullness.qual.MonotonicNonNull PluginRemapper pluginRemapper; // Paper PluginInitializerManager(final Path pluginDirectory, final Path updateDirectory) { this.pluginDirectory = pluginDirectory; this.updateDirectory = updateDirectory; - this.pluginRemapper = Boolean.getBoolean("paper.disablePluginRemapping") - ? null - : PluginRemapper.create(pluginDirectory); - LibraryLoader.REMAPPER = this.pluginRemapper == null ? Function.identity() : this.pluginRemapper::remapLibraries; } private static PluginInitializerManager parse(@NotNull final OptionSet minecraftOptionSet) throws Exception { @@ -107,7 +99,6 @@ public static void load(OptionSet optionSet) throws Exception { LOGGER.info("Initializing plugins..."); // We have to load the bukkit configuration inorder to get the update folder location. io.papermc.paper.plugin.PluginInitializerManager pluginSystem = io.papermc.paper.plugin.PluginInitializerManager.init(optionSet); - if (pluginSystem.pluginRemapper != null) pluginSystem.pluginRemapper.loadingPlugins(); // Register the default plugin directory io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.DirectoryProviderSource.INSTANCE, pluginSystem.pluginDirectoryPath()); diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java index 1240c061c121..4865f32084b8 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/BytecodeModifyingURLClassLoader.java @@ -1,6 +1,5 @@ package io.papermc.paper.plugin.entrypoint.classloader; -import io.papermc.paper.pluginremap.reflect.ReflectionRemapper; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -16,9 +15,6 @@ import java.util.jar.Attributes; import java.util.jar.Manifest; import org.checkerframework.checker.nullness.qual.Nullable; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; import static java.util.Objects.requireNonNullElse; @@ -45,16 +41,7 @@ public BytecodeModifyingURLClassLoader( final URL[] urls, final ClassLoader parent ) { - this(urls, parent, bytes -> { - final ClassReader classReader = new ClassReader(bytes); - final ClassWriter classWriter = new ClassWriter(classReader, 0); - final ClassVisitor visitor = ReflectionRemapper.visitor(classWriter); - if (visitor == classWriter) { - return bytes; - } - classReader.accept(visitor, 0); - return classWriter.toByteArray(); - }); + this(urls, parent, bytes -> bytes); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java index 0e734c07dbe8..f9a2c55a354c 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java @@ -7,6 +7,6 @@ public class PaperClassloaderBytecodeModifier implements ClassloaderBytecodeModi @Override public byte[] modify(PluginMeta configuration, byte[] bytecode) { - return io.papermc.paper.pluginremap.reflect.ReflectionRemapper.processClass(bytecode); + return bytecode; } } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java b/paper-server/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java index 21a0a4e29c0e..4bef544df4dc 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java @@ -1,13 +1,10 @@ package io.papermc.paper.plugin.loader; -import io.papermc.paper.plugin.PluginInitializerManager; import io.papermc.paper.plugin.bootstrap.PluginProviderContext; -import io.papermc.paper.plugin.entrypoint.classloader.BytecodeModifyingURLClassLoader; import io.papermc.paper.plugin.entrypoint.classloader.PaperPluginClassLoader; import io.papermc.paper.plugin.loader.library.ClassPathLibrary; import io.papermc.paper.plugin.loader.library.PaperLibraryStore; import io.papermc.paper.plugin.provider.configuration.PaperPluginMeta; -import io.papermc.paper.util.MappingEnvironment; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -41,7 +38,7 @@ public PaperClasspathBuilder(PluginProviderContext context) { } public PaperPluginClassLoader buildClassLoader(Logger logger, Path source, JarFile jarFile, PaperPluginMeta configuration) { - List paths = this.buildLibraryPaths(true); + List paths = this.buildLibraryPaths(); URL[] urls = new URL[paths.size()]; for (int i = 0; i < paths.size(); i++) { Path path = paths.get(i); @@ -53,25 +50,19 @@ public PaperPluginClassLoader buildClassLoader(Logger logger, Path source, JarFi } try { - final URLClassLoader libraryLoader = MappingEnvironment.DISABLE_PLUGIN_REMAPPING - ? new URLClassLoader(urls, this.getClass().getClassLoader()) - : new BytecodeModifyingURLClassLoader(urls, this.getClass().getClassLoader()); + final URLClassLoader libraryLoader = new URLClassLoader(urls, this.getClass().getClassLoader()); return new PaperPluginClassLoader(logger, source, jarFile, configuration, this.getClass().getClassLoader(), libraryLoader); } catch (IOException exception) { throw new RuntimeException(exception); } } - public List buildLibraryPaths(final boolean remap) { + public List buildLibraryPaths() { PaperLibraryStore paperLibraryStore = new PaperLibraryStore(); for (ClassPathLibrary library : this.libraries) { library.register(paperLibraryStore); } - List paths = paperLibraryStore.getPaths(); - if (remap && PluginInitializerManager.instance().pluginRemapper != null) { - paths = PluginInitializerManager.instance().pluginRemapper.remapLibraries(paths); - } - return paths; + return paperLibraryStore.getPaths(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/paper-server/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java index 4dd7c6c0d7f5..79f58fd01a16 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java @@ -343,7 +343,7 @@ private void flushAsyncAppenders() { for (final Appender appender : context.getConfiguration().getAppenders().values()) { if (appender instanceof AsyncAppender asyncAppender) { - final boolean flushed = asyncAppender.flush(100, TimeUnit.MILLISECONDS); + final boolean flushed = true; // TODO - snapshot - feature patches - asyncAppender.flush(100, TimeUnit.MILLISECONDS); if (!flushed) { this.server.getLogger().log(Level.WARNING, "Failed to flush log messages before plugin unload."); } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/DirectoryProviderSource.java b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/DirectoryProviderSource.java index 00dbd17a2378..b6dcbd88ea31 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/DirectoryProviderSource.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/DirectoryProviderSource.java @@ -18,7 +18,7 @@ public class DirectoryProviderSource implements ProviderSource> public static final DirectoryProviderSource INSTANCE = new DirectoryProviderSource(true); public static final DirectoryProviderSource INSTANCE_NO_CREATE = new DirectoryProviderSource(false); - private static final FileProviderSource FILE_PROVIDER_SOURCE = new FileProviderSource("Directory '%s'"::formatted, false); // Paper - Remap plugins + private static final FileProviderSource FILE_PROVIDER_SOURCE = new FileProviderSource("Directory '%s'"::formatted); private static final Logger LOGGER = LogUtils.getClassLogger(); private final boolean createDirectory; @@ -48,11 +48,6 @@ public List prepareContext(Path context) throws IOException { LOGGER.error("Error preparing plugin context: " + e.getMessage(), e); } }); - // Paper start - Remap plugins - if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) { - return io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.rewritePluginDirectory(files); - } - // Paper end - Remap plugins return files; } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/FileProviderSource.java b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/FileProviderSource.java index a0b84535a9d3..9661f033bbb2 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/FileProviderSource.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/FileProviderSource.java @@ -28,15 +28,9 @@ public class FileProviderSource implements ProviderSource { private static final Logger LOGGER = LogUtils.getClassLogger(); private final Function contextChecker; - private final boolean applyRemap; - - public FileProviderSource(Function contextChecker, boolean applyRemap) { - this.contextChecker = contextChecker; - this.applyRemap = applyRemap; - } public FileProviderSource(Function contextChecker) { - this(contextChecker, true); + this.contextChecker = contextChecker; } @Override @@ -60,11 +54,6 @@ public Path prepareContext(Path context) throws IOException { } catch (Exception exception) { throw new RuntimeException(source + " failed to update!", exception); } - // Paper start - Remap plugins - if (this.applyRemap && io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) { - context = io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.rewritePlugin(context); - } - // Paper end - Remap plugins return context; } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/PluginFlagProviderSource.java b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/PluginFlagProviderSource.java index c2b60c745135..ac55ae0e3011 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/PluginFlagProviderSource.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/provider/source/PluginFlagProviderSource.java @@ -14,7 +14,7 @@ public class PluginFlagProviderSource implements ProviderSource, List> { public static final PluginFlagProviderSource INSTANCE = new PluginFlagProviderSource(); - private static final FileProviderSource FILE_PROVIDER_SOURCE = new FileProviderSource("File '%s' specified through 'add-plugin' argument"::formatted, false); + private static final FileProviderSource FILE_PROVIDER_SOURCE = new FileProviderSource("File '%s' specified through 'add-plugin' argument"::formatted); private static final Logger LOGGER = LogUtils.getClassLogger(); @Override @@ -27,11 +27,6 @@ public List prepareContext(List context) { LOGGER.error("Error preparing plugin context: " + e.getMessage(), e); } } - // Paper start - Remap plugins - if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null && !files.isEmpty()) { - return io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.rewriteExtraPlugins(files); - } - // Paper end - Remap plugins return files; } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java b/paper-server/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java index 9edf79dffd28..5c40c3d0ea8e 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java @@ -2,20 +2,17 @@ import com.destroystokyo.paper.utils.PaperPluginLogger; import io.papermc.paper.plugin.bootstrap.PluginProviderContextImpl; -import io.papermc.paper.plugin.entrypoint.classloader.BytecodeModifyingURLClassLoader; import io.papermc.paper.plugin.entrypoint.classloader.PaperSimplePluginClassLoader; import io.papermc.paper.plugin.loader.PaperClasspathBuilder; import io.papermc.paper.plugin.loader.PluginLoader; import io.papermc.paper.plugin.provider.configuration.serializer.constraints.PluginConfigConstraints; import io.papermc.paper.plugin.provider.type.PluginTypeFactory; import io.papermc.paper.plugin.provider.util.ProviderUtil; -import io.papermc.paper.util.MappingEnvironment; import java.util.List; import java.util.logging.Logger; import net.kyori.adventure.text.logger.slf4j.ComponentLogger; import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.plugin.java.LibraryLoader; import org.yaml.snakeyaml.error.YAMLException; import java.io.IOException; @@ -27,12 +24,6 @@ class SpigotPluginProviderFactory implements PluginTypeFactory { - static { - if (!MappingEnvironment.DISABLE_PLUGIN_REMAPPING) { - LibraryLoader.LIBRARY_LOADER_FACTORY = BytecodeModifyingURLClassLoader::new; - } - } - @Override public SpigotPluginProvider build(JarFile file, PluginDescriptionFile configuration, Path source) throws InvalidDescriptionException { // Copied from SimplePluginManager#loadPlugins @@ -61,7 +52,7 @@ public SpigotPluginProvider build(JarFile file, PluginDescriptionFile configurat throw new RuntimeException(e); } - paperLibraryPaths = builder.buildLibraryPaths(false); + paperLibraryPaths = builder.buildLibraryPaths(); } else { paperLibraryPaths = null; } diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/DebugLogger.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/DebugLogger.java deleted file mode 100644 index 99e658e3a0f0..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/DebugLogger.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.papermc.paper.pluginremap; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.function.Consumer; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; - -/** - * {@link PrintWriter}-backed logger implementation for use with {@link net.neoforged.art.api.Renamer} which - * only opens the backing writer and logs messages when the {@link PluginRemapper#DEBUG_LOGGING} system property - * is set to true. - */ -@DefaultQualifier(NonNull.class) -final class DebugLogger implements Consumer, AutoCloseable { - private final @Nullable PrintWriter writer; - - DebugLogger(final Path logFile) { - try { - this.writer = createWriter(logFile); - } catch (final IOException ex) { - throw new RuntimeException("Failed to initialize DebugLogger for file '" + logFile + "'", ex); - } - } - - @Override - public void accept(final String line) { - this.useWriter(writer -> writer.println(line)); - } - - @Override - public void close() { - this.useWriter(PrintWriter::close); - } - - private void useWriter(final Consumer op) { - final @Nullable PrintWriter writer = this.writer; - if (writer != null) { - op.accept(writer); - } - } - - Consumer debug() { - return line -> this.accept("[debug]: " + line); - } - - static DebugLogger forOutputFile(final Path outputFile) { - return new DebugLogger(outputFile.resolveSibling(outputFile.getFileName() + ".log")); - } - - private static @Nullable PrintWriter createWriter(final Path logFile) throws IOException { - if (!PluginRemapper.DEBUG_LOGGING) { - return null; - } - if (!Files.exists(logFile.getParent())) { - Files.createDirectories(logFile.getParent()); - } - return new PrintWriter(logFile.toFile()); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/InsertManifestAttribute.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/InsertManifestAttribute.java deleted file mode 100644 index d738b31f0005..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/InsertManifestAttribute.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.papermc.paper.pluginremap; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.Manifest; -import net.neoforged.art.api.Transformer; - -final class InsertManifestAttribute implements Transformer { - static final String PAPERWEIGHT_NAMESPACE_MANIFEST_KEY = "paperweight-mappings-namespace"; - static final String MOJANG_NAMESPACE = "mojang"; - static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn"; - static final String SPIGOT_NAMESPACE = "spigot"; - static final Set KNOWN_NAMESPACES = Set.of(MOJANG_NAMESPACE, MOJANG_PLUS_YARN_NAMESPACE, SPIGOT_NAMESPACE); - - private final String mainAttributesKey; - private final String namespace; - private final boolean createIfMissing; - private volatile boolean visitedManifest = false; - - static Transformer addNamespaceManifestAttribute(final String namespace) { - return new InsertManifestAttribute(PAPERWEIGHT_NAMESPACE_MANIFEST_KEY, namespace, true); - } - - InsertManifestAttribute( - final String mainAttributesKey, - final String namespace, - final boolean createIfMissing - ) { - this.mainAttributesKey = mainAttributesKey; - this.namespace = namespace; - this.createIfMissing = createIfMissing; - } - - @Override - public ManifestEntry process(final ManifestEntry entry) { - this.visitedManifest = true; - try { - final Manifest manifest = new Manifest(new ByteArrayInputStream(entry.getData())); - manifest.getMainAttributes().putValue(this.mainAttributesKey, this.namespace); - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - manifest.write(out); - return ManifestEntry.create(Entry.STABLE_TIMESTAMP, out.toByteArray()); - } catch (final IOException e) { - throw new RuntimeException("Failed to modify manifest", e); - } - } - - @Override - public Collection getExtras() { - if (!this.visitedManifest && this.createIfMissing) { - final Manifest manifest = new Manifest(); - manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); - manifest.getMainAttributes().putValue(this.mainAttributesKey, this.namespace); - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - manifest.write(out); - } catch (final IOException e) { - throw new RuntimeException("Failed to write manifest", e); - } - return List.of(ManifestEntry.create(Entry.STABLE_TIMESTAMP, out.toByteArray())); - } - return Transformer.super.getExtras(); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/PluginRemapper.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/PluginRemapper.java deleted file mode 100644 index fbad4a2242aa..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/PluginRemapper.java +++ /dev/null @@ -1,442 +0,0 @@ -package io.papermc.paper.pluginremap; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.mojang.logging.LogUtils; -import io.papermc.paper.plugin.provider.type.PluginFileType; -import io.papermc.paper.util.AtomicFiles; -import io.papermc.paper.util.MappingEnvironment; -import io.papermc.paper.util.concurrent.ScalingThreadPool; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.jar.Manifest; -import java.util.stream.Stream; -import net.minecraft.DefaultUncaughtExceptionHandlerWithName; -import net.minecraft.util.ExceptionCollector; -import net.neoforged.art.api.Renamer; -import net.neoforged.art.api.SignatureStripperConfig; -import net.neoforged.art.api.Transformer; -import net.neoforged.srgutils.IMappingFile; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.slf4j.Logger; - -import static io.papermc.paper.pluginremap.InsertManifestAttribute.addNamespaceManifestAttribute; - -@DefaultQualifier(NonNull.class) -public final class PluginRemapper { - public static final boolean DEBUG_LOGGING = Boolean.getBoolean("Paper.PluginRemapperDebug"); - private static final String PAPER_REMAPPED = ".paper-remapped"; - private static final String UNKNOWN_ORIGIN = "unknown-origin"; - private static final String LIBRARIES = "libraries"; - private static final String EXTRA_PLUGINS = "extra-plugins"; - private static final String REMAP_CLASSPATH = "remap-classpath"; - private static final String REVERSED_MAPPINGS = "mappings/reversed"; - private static final Logger LOGGER = LogUtils.getClassLogger(); - - private final ExecutorService threadPool; - private final ReobfServer reobf; - private final RemappedPluginIndex remappedPlugins; - private final RemappedPluginIndex extraPlugins; - private final UnknownOriginRemappedPluginIndex unknownOrigin; - private final UnknownOriginRemappedPluginIndex libraries; - private @Nullable CompletableFuture reversedMappings; - - public PluginRemapper(final Path pluginsDir) { - this.threadPool = createThreadPool(); - final CompletableFuture mappings = CompletableFuture.supplyAsync(PluginRemapper::loadReobfMappings, this.threadPool); - final Path remappedPlugins = pluginsDir.resolve(PAPER_REMAPPED); - this.reversedMappings = this.reversedMappingsFuture(() -> mappings, remappedPlugins, this.threadPool); - this.reobf = new ReobfServer(remappedPlugins.resolve(REMAP_CLASSPATH), mappings, this.threadPool); - this.remappedPlugins = new RemappedPluginIndex(remappedPlugins, false); - this.extraPlugins = new RemappedPluginIndex(this.remappedPlugins.dir().resolve(EXTRA_PLUGINS), true); - this.unknownOrigin = new UnknownOriginRemappedPluginIndex(this.remappedPlugins.dir().resolve(UNKNOWN_ORIGIN)); - this.libraries = new UnknownOriginRemappedPluginIndex(this.remappedPlugins.dir().resolve(LIBRARIES)); - } - - public static @Nullable PluginRemapper create(final Path pluginsDir) { - if (MappingEnvironment.reobf() || !MappingEnvironment.hasMappings()) { - return null; - } - - try { - return new PluginRemapper(pluginsDir); - } catch (final Exception e) { - throw new RuntimeException("Failed to create PluginRemapper, try deleting the '" + pluginsDir.resolve(PAPER_REMAPPED) + "' directory", e); - } - } - - public void shutdown() { - this.threadPool.shutdown(); - this.save(true); - boolean didShutdown; - try { - didShutdown = this.threadPool.awaitTermination(3L, TimeUnit.SECONDS); - } catch (final InterruptedException ex) { - didShutdown = false; - } - if (!didShutdown) { - this.threadPool.shutdownNow(); - } - } - - public void save(final boolean clean) { - this.remappedPlugins.write(); - this.extraPlugins.write(); - this.unknownOrigin.write(clean); - this.libraries.write(clean); - } - - // Called on startup and reload - public void loadingPlugins() { - if (this.reversedMappings == null) { - this.reversedMappings = this.reversedMappingsFuture( - () -> CompletableFuture.supplyAsync(PluginRemapper::loadReobfMappings, this.threadPool), - this.remappedPlugins.dir(), - this.threadPool - ); - } - } - - // Called after all plugins enabled during startup/reload - public void pluginsEnabled() { - this.reversedMappings = null; - this.save(false); - } - - public List remapLibraries(final List libraries) { - final List> tasks = new ArrayList<>(); - for (final Path lib : libraries) { - if (!lib.getFileName().toString().endsWith(".jar")) { - if (DEBUG_LOGGING) { - LOGGER.info("Library '{}' is not a jar.", lib); - } - tasks.add(CompletableFuture.completedFuture(lib)); - continue; - } - final @Nullable Path cached = this.libraries.getIfPresent(lib); - if (cached != null) { - if (DEBUG_LOGGING) { - LOGGER.info("Library '{}' has not changed since last remap.", lib); - } - tasks.add(CompletableFuture.completedFuture(cached)); - continue; - } - tasks.add(this.remapLibrary(this.libraries, lib)); - } - return waitForAll(tasks); - } - - public Path rewritePlugin(final Path plugin) { - // Already remapped - if (plugin.getParent().equals(this.remappedPlugins.dir()) - || plugin.getParent().equals(this.extraPlugins.dir())) { - return plugin; - } - - final @Nullable Path cached = this.unknownOrigin.getIfPresent(plugin); - if (cached != null) { - if (DEBUG_LOGGING) { - LOGGER.info("Plugin '{}' has not changed since last remap.", plugin); - } - return cached; - } - - return this.remapPlugin(this.unknownOrigin, plugin).join(); - } - - public List rewriteExtraPlugins(final List plugins) { - final @Nullable List allCached = this.extraPlugins.getAllIfPresent(plugins); - if (allCached != null) { - if (DEBUG_LOGGING) { - LOGGER.info("All extra plugins have a remapped variant cached."); - } - return allCached; - } - - final List> tasks = new ArrayList<>(); - for (final Path file : plugins) { - final @Nullable Path cached = this.extraPlugins.getIfPresent(file); - if (cached != null) { - if (DEBUG_LOGGING) { - LOGGER.info("Extra plugin '{}' has not changed since last remap.", file); - } - tasks.add(CompletableFuture.completedFuture(cached)); - continue; - } - tasks.add(this.remapPlugin(this.extraPlugins, file)); - } - return waitForAll(tasks); - } - - public List rewritePluginDirectory(final List jars) { - final @Nullable List remappedJars = this.remappedPlugins.getAllIfPresent(jars); - if (remappedJars != null) { - if (DEBUG_LOGGING) { - LOGGER.info("All plugins have a remapped variant cached."); - } - return remappedJars; - } - - final List> tasks = new ArrayList<>(); - for (final Path file : jars) { - final @Nullable Path existingFile = this.remappedPlugins.getIfPresent(file); - if (existingFile != null) { - if (DEBUG_LOGGING) { - LOGGER.info("Plugin '{}' has not changed since last remap.", file); - } - tasks.add(CompletableFuture.completedFuture(existingFile)); - continue; - } - - tasks.add(this.remapPlugin(this.remappedPlugins, file)); - } - return waitForAll(tasks); - } - - private static IMappingFile reverse(final IMappingFile mappings) { - if (DEBUG_LOGGING) { - LOGGER.info("Reversing mappings..."); - } - final long start = System.currentTimeMillis(); - final IMappingFile reversed = mappings.reverse(); - if (DEBUG_LOGGING) { - LOGGER.info("Done reversing mappings in {}ms.", System.currentTimeMillis() - start); - } - return reversed; - } - - private CompletableFuture reversedMappingsFuture( - final Supplier> mappingsFuture, - final Path remappedPlugins, - final Executor executor - ) { - return CompletableFuture.supplyAsync(() -> { - try { - final String mappingsHash = MappingEnvironment.mappingsHash(); - final String fName = mappingsHash + ".tiny"; - final Path reversedMappings1 = remappedPlugins.resolve(REVERSED_MAPPINGS); - final Path file = reversedMappings1.resolve(fName); - if (Files.isDirectory(reversedMappings1)) { - if (Files.isRegularFile(file)) { - return CompletableFuture.completedFuture( - loadMappings("Reversed", Files.newInputStream(file)) - ); - } else { - for (final Path oldFile : list(reversedMappings1, Files::isRegularFile)) { - Files.delete(oldFile); - } - } - } else { - Files.createDirectories(reversedMappings1); - } - return mappingsFuture.get().thenApply(loadedMappings -> { - final IMappingFile reversed = reverse(loadedMappings); - try { - AtomicFiles.atomicWrite(file, writeTo -> { - reversed.write(writeTo, IMappingFile.Format.TINY, false); - }); - } catch (final IOException e) { - throw new RuntimeException("Failed to write reversed mappings", e); - } - return reversed; - }); - } catch (final IOException e) { - throw new RuntimeException("Failed to load reversed mappings", e); - } - }, executor).thenCompose(f -> f); - } - - private CompletableFuture remapPlugin( - final RemappedPluginIndex index, - final Path inputFile - ) { - return this.remap(index, inputFile, false); - } - - private CompletableFuture remapLibrary( - final RemappedPluginIndex index, - final Path inputFile - ) { - return this.remap(index, inputFile, true); - } - - /** - * Returns the remapped file if remapping was necessary, otherwise null. - * - * @param index remapped plugin index - * @param inputFile input file - * @return remapped file, or inputFile if no remapping was necessary - */ - private CompletableFuture remap( - final RemappedPluginIndex index, - final Path inputFile, - final boolean library - ) { - final Path destination = index.input(inputFile); - - try (final FileSystem fs = FileSystems.newFileSystem(inputFile, new HashMap<>())) { - // Leave dummy files if no remapping is required, so that we can check if they exist without copying the whole file - final Path manifestPath = fs.getPath("META-INF/MANIFEST.MF"); - final @Nullable String ns; - if (Files.exists(manifestPath)) { - final Manifest manifest; - try (final InputStream in = new BufferedInputStream(Files.newInputStream(manifestPath))) { - manifest = new Manifest(in); - } - ns = manifest.getMainAttributes().getValue(InsertManifestAttribute.PAPERWEIGHT_NAMESPACE_MANIFEST_KEY); - } else { - ns = null; - } - - if (ns != null && !InsertManifestAttribute.KNOWN_NAMESPACES.contains(ns)) { - throw new RuntimeException("Failed to remap plugin " + inputFile + " with unknown mapping namespace '" + ns + "'"); - } - - final boolean mojangMappedManifest = ns != null && (ns.equals(InsertManifestAttribute.MOJANG_NAMESPACE) || ns.equals(InsertManifestAttribute.MOJANG_PLUS_YARN_NAMESPACE)); - if (library) { - if (mojangMappedManifest) { - if (DEBUG_LOGGING) { - LOGGER.info("Library '{}' is already Mojang mapped.", inputFile); - } - index.skip(inputFile); - return CompletableFuture.completedFuture(inputFile); - } else if (ns == null) { - if (DEBUG_LOGGING) { - LOGGER.info("Library '{}' does not specify a mappings namespace (not remapping).", inputFile); - } - index.skip(inputFile); - return CompletableFuture.completedFuture(inputFile); - } - } else { - if (mojangMappedManifest) { - if (DEBUG_LOGGING) { - LOGGER.info("Plugin '{}' is already Mojang mapped.", inputFile); - } - index.skip(inputFile); - return CompletableFuture.completedFuture(inputFile); - } else if (ns == null && Files.exists(fs.getPath(PluginFileType.PAPER_PLUGIN_YML))) { - if (DEBUG_LOGGING) { - LOGGER.info("Plugin '{}' is a Paper plugin with no namespace specified.", inputFile); - } - index.skip(inputFile); - return CompletableFuture.completedFuture(inputFile); - } - } - } catch (final IOException ex) { - return CompletableFuture.failedFuture(new RuntimeException("Failed to open plugin jar " + inputFile, ex)); - } - - return this.reobf.remapped().thenApplyAsync(reobfServer -> { - LOGGER.info("Remapping {} '{}'...", library ? "library" : "plugin", inputFile); - final long start = System.currentTimeMillis(); - try (final DebugLogger logger = DebugLogger.forOutputFile(destination)) { - try (final Renamer renamer = Renamer.builder() - .add(Transformer.renamerFactory(this.mappings(), false)) - .add(addNamespaceManifestAttribute(InsertManifestAttribute.MOJANG_PLUS_YARN_NAMESPACE)) - .add(Transformer.signatureStripperFactory(SignatureStripperConfig.ALL)) - .lib(reobfServer.toFile()) - .threads(1) - .logger(logger) - .debug(logger.debug()) - .build()) { - renamer.run(inputFile.toFile(), destination.toFile()); - } - } catch (final Exception ex) { - throw new RuntimeException("Failed to remap plugin jar '" + inputFile + "'", ex); - } - LOGGER.info("Done remapping {} '{}' in {}ms.", library ? "library" : "plugin", inputFile, System.currentTimeMillis() - start); - return destination; - }, this.threadPool); - } - - private IMappingFile mappings() { - final @Nullable CompletableFuture mappings = this.reversedMappings; - if (mappings == null) { - return this.reversedMappingsFuture( - () -> CompletableFuture.supplyAsync(PluginRemapper::loadReobfMappings, Runnable::run), - this.remappedPlugins.dir(), - Runnable::run - ).join(); - } - return mappings.join(); - } - - private static IMappingFile loadReobfMappings() { - return loadMappings("Reobf", MappingEnvironment.mappingsStream()); - } - - private static IMappingFile loadMappings(final String name, final InputStream stream) { - try (stream) { - if (DEBUG_LOGGING) { - LOGGER.info("Loading {} mappings...", name); - } - final long start = System.currentTimeMillis(); - final IMappingFile load = IMappingFile.load(stream); - if (DEBUG_LOGGING) { - LOGGER.info("Done loading {} mappings in {}ms.", name, System.currentTimeMillis() - start); - } - return load; - } catch (final IOException ex) { - throw new RuntimeException("Failed to load " + name + " mappings", ex); - } - } - - static List list(final Path dir, final Predicate filter) { - try (final Stream stream = Files.list(dir)) { - return stream.filter(filter).toList(); - } catch (final IOException ex) { - throw new RuntimeException("Failed to list directory '" + dir + "'", ex); - } - } - - private static List waitForAll(final List> tasks) { - final ExceptionCollector collector = new ExceptionCollector<>(); - final List ret = new ArrayList<>(); - for (final CompletableFuture task : tasks) { - try { - ret.add(task.join()); - } catch (final CompletionException ex) { - collector.add(ex); - } - } - try { - collector.throwIfPresent(); - } catch (final Exception ex) { - // Don't hard fail during bootstrap/plugin loading. The plugin(s) in question will be skipped - LOGGER.error("Encountered exception remapping plugins", ex); - } - return ret; - } - - private static ThreadPoolExecutor createThreadPool() { - return new ThreadPoolExecutor( - 0, - 4, - 5L, - TimeUnit.SECONDS, - ScalingThreadPool.createUnboundedQueue(), - new ThreadFactoryBuilder() - .setNameFormat("Paper Plugin Remapper Thread - %1$d") - .setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)) - .build(), - ScalingThreadPool.defaultReEnqueuePolicy() - ); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/RemappedPluginIndex.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/RemappedPluginIndex.java deleted file mode 100644 index 1a2e8902c060..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/RemappedPluginIndex.java +++ /dev/null @@ -1,217 +0,0 @@ -package io.papermc.paper.pluginremap; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.mojang.logging.LogUtils; -import io.papermc.paper.util.Hashing; -import io.papermc.paper.util.MappingEnvironment; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.slf4j.Logger; -import org.spongepowered.configurate.loader.AtomicFiles; - -@DefaultQualifier(NonNull.class) -class RemappedPluginIndex { - private static final Logger LOGGER = LogUtils.getLogger(); - private static final Gson GSON = new GsonBuilder() - .setPrettyPrinting() - .create(); - private static final String INDEX_FILE_NAME = "index.json"; - - protected final State state; - private final Path dir; - private final Path indexFile; - private final boolean handleDuplicateFileNames; - - // todo maybe hash remapped variants to ensure they haven't changed? probably unneeded - static final class State { - final Map hashes = new HashMap<>(); - final Set skippedHashes = new HashSet<>(); - private final String mappingsHash = MappingEnvironment.mappingsHash(); - } - - RemappedPluginIndex(final Path dir, final boolean handleDuplicateFileNames) { - this.dir = dir; - this.handleDuplicateFileNames = handleDuplicateFileNames; - if (!Files.exists(this.dir)) { - try { - Files.createDirectories(this.dir); - } catch (final IOException ex) { - throw new UncheckedIOException(ex); - } - } - - this.indexFile = dir.resolve(INDEX_FILE_NAME); - if (Files.isRegularFile(this.indexFile)) { - this.state = this.readIndex(); - } else { - this.state = new State(); - } - } - - private State readIndex() { - final State state; - try (final BufferedReader reader = Files.newBufferedReader(this.indexFile)) { - state = GSON.fromJson(reader, State.class); - } catch (final Exception ex) { - throw new RuntimeException("Failed to read index file '" + this.indexFile + "'", ex); - } - - // If mappings have changed, delete all cached files and create a new index - if (!state.mappingsHash.equals(MappingEnvironment.mappingsHash())) { - for (final String fileName : state.hashes.values()) { - final Path path = this.dir.resolve(fileName); - try { - Files.deleteIfExists(path); - } catch (final IOException ex) { - throw new UncheckedIOException("Failed to delete no longer needed file '" + path + "'", ex); - } - } - return new State(); - } - return state; - } - - Path dir() { - return this.dir; - } - - /** - * Returns a list of cached paths if all of the input paths are present in the cache. - * The returned list may contain paths from different directories. - * - * @param paths plugin jar paths to check - * @return null if any of the paths are not present in the cache, otherwise a list of the cached paths - */ - @Nullable List getAllIfPresent(final List paths) { - final Map hashCache = new HashMap<>(); - final Function inputFileHash = path -> hashCache.computeIfAbsent(path, Hashing::sha256); - - // Delete cached entries we no longer need - final Iterator> iterator = this.state.hashes.entrySet().iterator(); - while (iterator.hasNext()) { - final Map.Entry entry = iterator.next(); - final String inputHash = entry.getKey(); - final String fileName = entry.getValue(); - if (paths.stream().anyMatch(path -> inputFileHash.apply(path).equals(inputHash))) { - // Hash is used, keep it - continue; - } - - iterator.remove(); - final Path filePath = this.dir.resolve(fileName); - try { - Files.deleteIfExists(filePath); - } catch (final IOException ex) { - throw new UncheckedIOException("Failed to delete no longer needed file '" + filePath + "'", ex); - } - } - - // Also clear hashes of skipped files - this.state.skippedHashes.removeIf(hash -> paths.stream().noneMatch(path -> inputFileHash.apply(path).equals(hash))); - - final List ret = new ArrayList<>(); - for (final Path path : paths) { - final String inputHash = inputFileHash.apply(path); - if (this.state.skippedHashes.contains(inputHash)) { - // Add the original path - ret.add(path); - continue; - } - - final @Nullable Path cached = this.getIfPresent(inputHash); - if (cached == null) { - // Missing the remapped file - return null; - } - ret.add(cached); - } - return ret; - } - - private String createCachedFileName(final Path in) { - if (this.handleDuplicateFileNames) { - final String fileName = in.getFileName().toString(); - final int i = fileName.lastIndexOf(".jar"); - return fileName.substring(0, i) + "-" + System.currentTimeMillis() + ".jar"; - } - return in.getFileName().toString(); - } - - /** - * Returns the given path if the file was previously skipped for being remapped, otherwise the cached path or null. - * - * @param in input file - * @return {@code in} if already remapped, the cached path if present, otherwise null - */ - @Nullable Path getIfPresent(final Path in) { - final String inHash = Hashing.sha256(in); - if (this.state.skippedHashes.contains(inHash)) { - return in; - } - return this.getIfPresent(inHash); - } - - /** - * Returns the cached path if a remapped file is present for the given hash, otherwise null. - * - * @param inHash hash of the input file - * @return the cached path if present, otherwise null - * @see #getIfPresent(Path) - */ - protected @Nullable Path getIfPresent(final String inHash) { - final @Nullable String fileName = this.state.hashes.get(inHash); - if (fileName == null) { - return null; - } - - final Path path = this.dir.resolve(fileName); - if (Files.exists(path)) { - return path; - } - return null; - } - - Path input(final Path in) { - return this.input(in, Hashing.sha256(in)); - } - - /** - * Marks the given file as skipped for remapping. - * - * @param in input file - */ - void skip(final Path in) { - this.state.skippedHashes.add(Hashing.sha256(in)); - } - - protected Path input(final Path in, final String hashString) { - final String name = this.createCachedFileName(in); - this.state.hashes.put(hashString, name); - return this.dir.resolve(name); - } - - void write() { - try (final BufferedWriter writer = AtomicFiles.atomicBufferedWriter(this.indexFile, StandardCharsets.UTF_8)) { - GSON.toJson(this.state, writer); - } catch (final IOException ex) { - LOGGER.warn("Failed to write index file '{}'", this.indexFile, ex); - } - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/ReobfServer.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/ReobfServer.java deleted file mode 100644 index aa5bf7ae042f..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/ReobfServer.java +++ /dev/null @@ -1,92 +0,0 @@ -package io.papermc.paper.pluginremap; - -import com.mojang.logging.LogUtils; -import io.papermc.paper.util.AtomicFiles; -import io.papermc.paper.util.MappingEnvironment; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import net.neoforged.art.api.Renamer; -import net.neoforged.art.api.Transformer; -import net.neoforged.art.internal.RenamerImpl; -import net.neoforged.srgutils.IMappingFile; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.slf4j.Logger; - -import static io.papermc.paper.pluginremap.InsertManifestAttribute.addNamespaceManifestAttribute; - -@DefaultQualifier(NonNull.class) -final class ReobfServer { - private static final Logger LOGGER = LogUtils.getClassLogger(); - - private final Path remapClasspathDir; - private final CompletableFuture load; - - ReobfServer(final Path remapClasspathDir, final CompletableFuture mappings, final Executor executor) { - this.remapClasspathDir = remapClasspathDir; - if (this.mappingsChanged()) { - this.load = mappings.thenAcceptAsync(this::remap, executor); - } else { - if (PluginRemapper.DEBUG_LOGGING) { - LOGGER.info("Have cached reobf server for current mappings."); - } - this.load = CompletableFuture.completedFuture(null); - } - } - - CompletableFuture remapped() { - return this.load.thenApply($ -> this.remappedPath()); - } - - private Path remappedPath() { - return this.remapClasspathDir.resolve(MappingEnvironment.mappingsHash() + ".jar"); - } - - private boolean mappingsChanged() { - return !Files.exists(this.remappedPath()); - } - - private void remap(final IMappingFile mappings) { - try { - if (!Files.exists(this.remapClasspathDir)) { - Files.createDirectories(this.remapClasspathDir); - } - for (final Path file : PluginRemapper.list(this.remapClasspathDir, Files::isRegularFile)) { - Files.delete(file); - } - } catch (final IOException ex) { - throw new RuntimeException(ex); - } - - LOGGER.info("Remapping server..."); - final long startRemap = System.currentTimeMillis(); - try (final DebugLogger log = DebugLogger.forOutputFile(this.remappedPath())) { - AtomicFiles.atomicWrite(this.remappedPath(), writeTo -> { - try (final RenamerImpl renamer = (RenamerImpl) Renamer.builder() - .logger(log) - .debug(log.debug()) - .threads(1) - .add(Transformer.renamerFactory(mappings, false)) - .add(addNamespaceManifestAttribute(InsertManifestAttribute.SPIGOT_NAMESPACE)) - .build()) { - renamer.run(serverJar().toFile(), writeTo.toFile(), true); - } - }); - } catch (final Exception ex) { - throw new RuntimeException("Failed to remap server jar", ex); - } - LOGGER.info("Done remapping server in {}ms.", System.currentTimeMillis() - startRemap); - } - - private static Path serverJar() { - try { - return Path.of(ReobfServer.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (final URISyntaxException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/UnknownOriginRemappedPluginIndex.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/UnknownOriginRemappedPluginIndex.java deleted file mode 100644 index ad53aab4fee1..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/UnknownOriginRemappedPluginIndex.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.papermc.paper.pluginremap; - -import com.mojang.logging.LogUtils; -import io.papermc.paper.util.Hashing; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.slf4j.Logger; - -@DefaultQualifier(NonNull.class) -final class UnknownOriginRemappedPluginIndex extends RemappedPluginIndex { - private static final Logger LOGGER = LogUtils.getLogger(); - - private final Set used = new HashSet<>(); - - UnknownOriginRemappedPluginIndex(final Path dir) { - super(dir, true); - } - - @Override - @Nullable Path getIfPresent(final Path in) { - final String hash = Hashing.sha256(in); - if (this.state.skippedHashes.contains(hash)) { - return in; - } - - final @Nullable Path path = super.getIfPresent(hash); - if (path != null) { - this.used.add(hash); - } - return path; - } - - @Override - Path input(final Path in) { - final String hash = Hashing.sha256(in); - this.used.add(hash); - return super.input(in, hash); - } - - void write(final boolean clean) { - if (!clean) { - super.write(); - return; - } - - final Iterator> it = this.state.hashes.entrySet().iterator(); - while (it.hasNext()) { - final Map.Entry next = it.next(); - if (this.used.contains(next.getKey())) { - continue; - } - - // Remove unused mapped file - it.remove(); - final Path file = this.dir().resolve(next.getValue()); - try { - Files.deleteIfExists(file); - } catch (final IOException ex) { - LOGGER.warn("Failed to delete no longer needed cached jar '{}'", file, ex); - } - } - super.write(); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java deleted file mode 100644 index 92bc8e4933ff..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/PaperReflection.java +++ /dev/null @@ -1,211 +0,0 @@ -package io.papermc.paper.pluginremap.reflect; - -import com.mojang.logging.LogUtils; -import io.papermc.paper.util.MappingEnvironment; -import io.papermc.paper.util.ObfHelper; -import io.papermc.reflectionrewriter.runtime.AbstractDefaultRulesReflectionProxy; -import io.papermc.reflectionrewriter.runtime.DefineClassReflectionProxy; -import java.lang.invoke.MethodHandles; -import java.nio.ByteBuffer; -import java.security.CodeSource; -import java.security.ProtectionDomain; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.slf4j.Logger; - -// todo proper inheritance handling -@SuppressWarnings("unused") -@DefaultQualifier(NonNull.class) -public final class PaperReflection extends AbstractDefaultRulesReflectionProxy implements DefineClassReflectionProxy { - // concat to avoid being rewritten by shadow - private static final Logger LOGGER = LogUtils.getLogger(); - private static final String CB_PACKAGE_PREFIX = "org.bukkit.".concat("craftbukkit."); - private static final String LEGACY_CB_PACKAGE_PREFIX = "org.bukkit.".concat("craftbukkit.") + MappingEnvironment.LEGACY_CB_VERSION + "."; - - private final DefineClassReflectionProxy defineClassProxy; - private final Map mappingsByMojangName; - private final Map mappingsByObfName; - // Reflection does not care about method return values, so this map removes the return value descriptor from the key - private final Map> strippedMethodMappings; - - PaperReflection() { - this.defineClassProxy = DefineClassReflectionProxy.create(PaperReflection::processClass); - if (!MappingEnvironment.hasMappings()) { - this.mappingsByMojangName = Map.of(); - this.mappingsByObfName = Map.of(); - this.strippedMethodMappings = Map.of(); - return; - } - final ObfHelper obfHelper = ObfHelper.INSTANCE; - this.mappingsByMojangName = Objects.requireNonNull(obfHelper.mappingsByMojangName(), "mappingsByMojangName"); - this.mappingsByObfName = Objects.requireNonNull(obfHelper.mappingsByObfName(), "mappingsByObfName"); - this.strippedMethodMappings = this.mappingsByMojangName.entrySet().stream().collect(Collectors.toUnmodifiableMap( - Map.Entry::getKey, - entry -> entry.getValue().strippedMethods() - )); - } - - @Override - protected String mapClassName(final String name) { - final ObfHelper.@Nullable ClassMapping mapping = this.mappingsByObfName.get(name); - return mapping != null ? mapping.mojangName() : removeCraftBukkitRelocation(name); - } - - @Override - protected String mapDeclaredMethodName(final Class clazz, final String name, final Class @Nullable ... parameterTypes) { - final @Nullable Map mapping = this.strippedMethodMappings.get(clazz.getName()); - if (mapping == null) { - return name; - } - return mapping.getOrDefault(strippedMethodKey(name, parameterTypes), name); - } - - @Override - protected String mapMethodName(final Class clazz, final String name, final Class @Nullable ... parameterTypes) { - final @Nullable String mapped = this.findMappedMethodName(clazz, name, parameterTypes); - return mapped != null ? mapped : name; - } - - @Override - protected String mapDeclaredFieldName(final Class clazz, final String name) { - final ObfHelper.@Nullable ClassMapping mapping = this.mappingsByMojangName.get(clazz.getName()); - if (mapping == null) { - return name; - } - return mapping.fieldsByObf().getOrDefault(name, name); - } - - @Override - protected String mapFieldName(final Class clazz, final String name) { - final @Nullable String mapped = this.findMappedFieldName(clazz, name); - return mapped != null ? mapped : name; - } - - private @Nullable String findMappedMethodName(final Class clazz, final String name, final Class @Nullable ... parameterTypes) { - final Map map = this.strippedMethodMappings.get(clazz.getName()); - @Nullable String mapped = null; - if (map != null) { - mapped = map.get(strippedMethodKey(name, parameterTypes)); - if (mapped != null) { - return mapped; - } - } - // JVM checks super before interfaces - final Class superClass = clazz.getSuperclass(); - if (superClass != null) { - mapped = this.findMappedMethodName(superClass, name, parameterTypes); - } - if (mapped == null) { - for (final Class i : clazz.getInterfaces()) { - mapped = this.findMappedMethodName(i, name, parameterTypes); - if (mapped != null) { - break; - } - } - } - return mapped; - } - - private @Nullable String findMappedFieldName(final Class clazz, final String name) { - final ObfHelper.ClassMapping mapping = this.mappingsByMojangName.get(clazz.getName()); - @Nullable String mapped = null; - if (mapping != null) { - mapped = mapping.fieldsByObf().get(name); - if (mapped != null) { - return mapped; - } - } - // The JVM checks super before interfaces - final Class superClass = clazz.getSuperclass(); - if (superClass != null) { - mapped = this.findMappedFieldName(superClass, name); - } - if (mapped == null) { - for (final Class i : clazz.getInterfaces()) { - mapped = this.findMappedFieldName(i, name); - if (mapped != null) { - break; - } - } - } - return mapped; - } - - private static String strippedMethodKey(final String methodName, final Class @Nullable ... parameterTypes) { - return methodName + parameterDescriptor(parameterTypes); - } - - private static String parameterDescriptor(final Class @Nullable ... parameterTypes) { - if (parameterTypes == null) { - // Null parameterTypes is treated as an empty array - return "()"; - } - final StringBuilder builder = new StringBuilder(); - builder.append('('); - for (final Class parameterType : parameterTypes) { - builder.append(parameterType.descriptorString()); - } - builder.append(')'); - return builder.toString(); - } - - private static String removeCraftBukkitRelocation(final String name) { - if (MappingEnvironment.hasMappings()) { - // Relocation is applied in reobf, and when mappings are present they handle the relocation - return name; - } - if (name.startsWith(LEGACY_CB_PACKAGE_PREFIX)) { - return CB_PACKAGE_PREFIX + name.substring(LEGACY_CB_PACKAGE_PREFIX.length()); - } - return name; - } - - @Override - public Class defineClass(final Object loader, final byte[] b, final int off, final int len) throws ClassFormatError { - return this.defineClassProxy.defineClass(loader, b, off, len); - } - - @Override - public Class defineClass(final Object loader, final String name, final byte[] b, final int off, final int len) throws ClassFormatError { - return this.defineClassProxy.defineClass(loader, name, b, off, len); - } - - @Override - public Class defineClass(final Object loader, final @Nullable String name, final byte[] b, final int off, final int len, final @Nullable ProtectionDomain protectionDomain) throws ClassFormatError { - return this.defineClassProxy.defineClass(loader, name, b, off, len, protectionDomain); - } - - @Override - public Class defineClass(final Object loader, final String name, final ByteBuffer b, final ProtectionDomain protectionDomain) throws ClassFormatError { - return this.defineClassProxy.defineClass(loader, name, b, protectionDomain); - } - - @Override - public Class defineClass(final Object secureLoader, final String name, final byte[] b, final int off, final int len, final CodeSource cs) { - return this.defineClassProxy.defineClass(secureLoader, name, b, off, len, cs); - } - - @Override - public Class defineClass(final Object secureLoader, final String name, final ByteBuffer b, final CodeSource cs) { - return this.defineClassProxy.defineClass(secureLoader, name, b, cs); - } - - @Override - public Class defineClass(final MethodHandles.Lookup lookup, final byte[] bytes) throws IllegalAccessException { - return this.defineClassProxy.defineClass(lookup, bytes); - } - - // todo apply bytecode remap here as well - private static byte[] processClass(final byte[] bytes) { - try { - return ReflectionRemapper.processClass(bytes); - } catch (final Exception ex) { - LOGGER.warn("Failed to process class bytes", ex); - return bytes; - } - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java b/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java deleted file mode 100644 index a3045afbc0cc..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/pluginremap/reflect/ReflectionRemapper.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.papermc.paper.pluginremap.reflect; - -import io.papermc.asm.ClassInfoProvider; -import io.papermc.asm.RewriteRuleVisitorFactory; -import io.papermc.paper.util.MappingEnvironment; -import io.papermc.reflectionrewriter.BaseReflectionRules; -import io.papermc.reflectionrewriter.DefineClassRule; -import io.papermc.reflectionrewriter.proxygenerator.ProxyGenerator; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Method; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.framework.qual.DefaultQualifier; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; - -@DefaultQualifier(NonNull.class) -public final class ReflectionRemapper { - private static final String PAPER_REFLECTION_HOLDER = "io.papermc.paper.pluginremap.reflect.PaperReflectionHolder"; - private static final String PAPER_REFLECTION_HOLDER_DESC = PAPER_REFLECTION_HOLDER.replace('.', '/'); - private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create( - Opcodes.ASM9, - chain -> chain.then(new BaseReflectionRules(PAPER_REFLECTION_HOLDER).rules()) - .then(DefineClassRule.create(PAPER_REFLECTION_HOLDER_DESC, true)), - ClassInfoProvider.basic() - ); - - static { - if (!MappingEnvironment.reobf()) { - setupProxy(); - } - } - - private ReflectionRemapper() { - } - - public static ClassVisitor visitor(final ClassVisitor parent) { - if (MappingEnvironment.reobf() || MappingEnvironment.DISABLE_PLUGIN_REMAPPING) { - return parent; - } - return VISITOR_FACTORY.createVisitor(parent); - } - - public static byte[] processClass(final byte[] bytes) { - if (MappingEnvironment.DISABLE_PLUGIN_REMAPPING) { - return bytes; - } - final ClassReader classReader = new ClassReader(bytes); - final ClassWriter classWriter = new ClassWriter(classReader, 0); - classReader.accept(ReflectionRemapper.visitor(classWriter), 0); - return classWriter.toByteArray(); - } - - private static void setupProxy() { - try { - final byte[] bytes = ProxyGenerator.generateProxy(PaperReflection.class, PAPER_REFLECTION_HOLDER_DESC); - final MethodHandles.Lookup lookup = MethodHandles.lookup(); - final Class generated = lookup.defineClass(bytes); - final Method init = generated.getDeclaredMethod("init", PaperReflection.class); - init.invoke(null, new PaperReflection()); - } catch (final ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/raytracing/PositionedRayTraceConfigurationBuilderImpl.java b/paper-server/src/main/java/io/papermc/paper/raytracing/PositionedRayTraceConfigurationBuilderImpl.java index 178e58292358..cb8d66555358 100644 --- a/paper-server/src/main/java/io/papermc/paper/raytracing/PositionedRayTraceConfigurationBuilderImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/raytracing/PositionedRayTraceConfigurationBuilderImpl.java @@ -20,7 +20,7 @@ public class PositionedRayTraceConfigurationBuilderImpl implements PositionedRay public OptionalDouble maxDistance = OptionalDouble.empty(); public FluidCollisionMode fluidCollisionMode = FluidCollisionMode.NEVER; public BlockCollisionMode blockCollisionMode = BlockCollisionMode.OUTLINE; - public double raySize = 0.0D; + public double raySize = 0.0; public @Nullable Predicate entityFilter; public @Nullable Predicate blockFilter; public EnumSet targets = EnumSet.noneOf(RayTraceTarget.class); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index 121babcfdda5..291b47d91a4b 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -136,10 +136,14 @@ public final class PaperRegistries { start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(), start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new, true).writable(PaperInstrumentRegistryEntry.PaperBuilder::new).delayed(), start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).writable(PaperCatTypeRegistryEntry.PaperBuilder::new).delayed(), + start(Registries.CAT_SOUND_VARIANT, RegistryKey.CAT_SOUND_VARIANT).craft(Cat.SoundVariant.class, CraftCat.CraftSoundVariant::new).build(), start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).writable(PaperFrogVariantRegistryEntry.PaperBuilder::new).delayed(), start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).writable(PaperChickenVariantRegistryEntry.PaperBuilder::new), + start(Registries.CHICKEN_SOUND_VARIANT, RegistryKey.CHICKEN_SOUND_VARIANT).craft(Chicken.SoundVariant.class, CraftChicken.CraftSoundVariant::new).build(), start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).writable(PaperCowVariantRegistryEntry.PaperBuilder::new), + start(Registries.COW_SOUND_VARIANT, RegistryKey.COW_SOUND_VARIANT).craft(Cow.SoundVariant.class, CraftCow.CraftSoundVariant::new).build(), start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).writable(PaperPigVariantRegistryEntry.PaperBuilder::new), + start(Registries.PIG_SOUND_VARIANT, RegistryKey.PIG_SOUND_VARIANT).craft(Pig.SoundVariant.class, CraftPig.CraftSoundVariant::new).build(), start(Registries.ZOMBIE_NAUTILUS_VARIANT, RegistryKey.ZOMBIE_NAUTILUS_VARIANT).craft(ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant::new).writable(PaperZombieNautilusVariantRegistryEntry.PaperBuilder::new), start(Registries.DIALOG, RegistryKey.DIALOG).craft(Dialog.class, PaperDialog::new, true).writable(PaperDialogRegistryEntry.PaperBuilder::new), diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCatTypeRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCatTypeRegistryEntry.java index 7b73a4a8e549..a1d314f722d9 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCatTypeRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCatTypeRegistryEntry.java @@ -15,6 +15,7 @@ public class PaperCatTypeRegistryEntry implements CatTypeRegistryEntry { protected ClientAsset.@Nullable ResourceTexture clientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyClientTextureAsset; protected SpawnPrioritySelectors spawnConditions; protected final Conversions conversions; @@ -29,7 +30,8 @@ public PaperCatTypeRegistryEntry( return; } - this.clientTextureAsset = internal.assetInfo(); + this.clientTextureAsset = internal.assetInfo(false); + this.babyClientTextureAsset = internal.assetInfo(true); this.spawnConditions = internal.spawnConditions(); } @@ -38,6 +40,11 @@ public ClientTextureAsset clientTextureAsset() { return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset")); } + @Override + public ClientTextureAsset babyClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset")); + } + public static final class PaperBuilder extends PaperCatTypeRegistryEntry implements Builder, PaperRegistryBuilder { public PaperBuilder(final Conversions conversions, final @Nullable CatVariant internal) { @@ -50,10 +57,17 @@ public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) { return this; } + @Override + public Builder babyClientTextureAsset(final ClientTextureAsset babyClientTextureAsset) { + this.babyClientTextureAsset = this.conversions.asVanilla(asArgument(babyClientTextureAsset, "babyClientTextureAsset")); + return this; + } + @Override public CatVariant build() { return new CatVariant( asConfigured(this.clientTextureAsset, "clientTextureAsset"), + asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset"), asConfigured(this.spawnConditions, "spawnConditions") ); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperChickenVariantRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperChickenVariantRegistryEntry.java index 31b931326467..4809bff29b99 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperChickenVariantRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperChickenVariantRegistryEntry.java @@ -17,6 +17,7 @@ public class PaperChickenVariantRegistryEntry implements ChickenVariantRegistryE protected ChickenVariant.@Nullable ModelType model; protected ClientAsset.@Nullable ResourceTexture clientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyClientTextureAsset; protected SpawnPrioritySelectors spawnConditions; protected final Conversions conversions; @@ -32,6 +33,7 @@ public PaperChickenVariantRegistryEntry( } this.clientTextureAsset = internal.modelAndTexture().asset(); + this.babyClientTextureAsset = internal.babyTexture(); this.model = internal.modelAndTexture().model(); this.spawnConditions = internal.spawnConditions(); } @@ -41,6 +43,11 @@ public ClientTextureAsset clientTextureAsset() { return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset")); } + @Override + public ClientTextureAsset babyClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset")); + } + @Override public Model model() { return switch (asConfigured(this.model, "model")) { @@ -61,6 +68,12 @@ public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) { return this; } + @Override + public Builder babyClientTextureAsset(final ClientTextureAsset babyClientTextureAsset) { + this.babyClientTextureAsset = this.conversions.asVanilla(asArgument(babyClientTextureAsset, "babyClientTextureAsset")); + return this; + } + @Override public Builder model(final Model model) { this.model = switch (asArgument(model, "model")) { @@ -74,6 +87,7 @@ public Builder model(final Model model) { public ChickenVariant build() { return new ChickenVariant( new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")), + asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset"), asConfigured(this.spawnConditions, "spawnConditions") ); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCowVariantRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCowVariantRegistryEntry.java index cd3249196b26..8d526716ea43 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCowVariantRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperCowVariantRegistryEntry.java @@ -17,6 +17,7 @@ public class PaperCowVariantRegistryEntry implements CowVariantRegistryEntry { protected CowVariant.@Nullable ModelType model = null; protected ClientAsset.@Nullable ResourceTexture clientTextureAsset = null; + protected ClientAsset.@Nullable ResourceTexture babyClientTextureAsset = null; protected SpawnPrioritySelectors spawnConditions; protected final Conversions conversions; @@ -32,6 +33,7 @@ public PaperCowVariantRegistryEntry( } this.clientTextureAsset = internal.modelAndTexture().asset(); + this.babyClientTextureAsset = internal.babyTexture(); this.model = internal.modelAndTexture().model(); this.spawnConditions = internal.spawnConditions(); } @@ -41,6 +43,11 @@ public ClientTextureAsset clientTextureAsset() { return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset")); } + @Override + public ClientTextureAsset babyClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset")); + } + @Override public Model model() { return switch (asConfigured(this.model, "model")) { @@ -62,6 +69,12 @@ public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) { return this; } + @Override + public Builder babyClientTextureAsset(final ClientTextureAsset babyClientTextureAsset) { + this.babyClientTextureAsset = this.conversions.asVanilla(asArgument(babyClientTextureAsset, "babyClientTextureAsset")); + return this; + } + @Override public Builder model(final Model model) { this.model = switch (asArgument(model, "model")) { @@ -76,6 +89,7 @@ public Builder model(final Model model) { public CowVariant build() { return new CowVariant( new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")), + asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset"), this.spawnConditions ); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperPigVariantRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperPigVariantRegistryEntry.java index 3f8af47de16b..fe9e5889b819 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperPigVariantRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperPigVariantRegistryEntry.java @@ -17,6 +17,7 @@ public class PaperPigVariantRegistryEntry implements PigVariantRegistryEntry { protected PigVariant.@Nullable ModelType model; protected ClientAsset.@Nullable ResourceTexture clientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyClientTextureAsset; protected SpawnPrioritySelectors spawnConditions; protected final Conversions conversions; @@ -32,6 +33,7 @@ public PaperPigVariantRegistryEntry( } this.clientTextureAsset = internal.modelAndTexture().asset(); + this.babyClientTextureAsset = internal.babyTexture(); this.model = internal.modelAndTexture().model(); this.spawnConditions = internal.spawnConditions(); } @@ -41,6 +43,11 @@ public ClientTextureAsset clientTextureAsset() { return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset")); } + @Override + public ClientTextureAsset babyClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset")); + } + @Override public Model model() { return switch (asConfigured(this.model, "model")) { @@ -61,6 +68,12 @@ public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) { return this; } + @Override + public Builder babyClientTextureAsset(final ClientTextureAsset babyClientTextureAsset) { + this.babyClientTextureAsset = this.conversions.asVanilla(asArgument(babyClientTextureAsset, "babyClientTextureAsset")); + return this; + } + @Override public Builder model(final Model model) { this.model = switch (asArgument(model, "model")) { @@ -74,6 +87,7 @@ public Builder model(final Model model) { public PigVariant build() { return new PigVariant( new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")), + asConfigured(this.babyClientTextureAsset, "babyClientTextureAsset"), asConfigured(this.spawnConditions, "spawnConditions") ); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperWolfVariantRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperWolfVariantRegistryEntry.java index cb7a976b4ad1..4c33b3ecd8a2 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperWolfVariantRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperWolfVariantRegistryEntry.java @@ -17,6 +17,9 @@ public class PaperWolfVariantRegistryEntry implements WolfVariantRegistryEntry { protected ClientAsset.@Nullable ResourceTexture angryClientTextureAsset; protected ClientAsset.@Nullable ResourceTexture wildClientTextureAsset; protected ClientAsset.@Nullable ResourceTexture tameClientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyAngryClientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyWildClientTextureAsset; + protected ClientAsset.@Nullable ResourceTexture babyTameClientTextureAsset; protected SpawnPrioritySelectors spawnConditions; protected final Conversions conversions; @@ -31,9 +34,12 @@ public PaperWolfVariantRegistryEntry( return; } - this.angryClientTextureAsset = internal.assetInfo().angry(); - this.wildClientTextureAsset = internal.assetInfo().wild(); - this.tameClientTextureAsset = internal.assetInfo().tame(); + this.angryClientTextureAsset = internal.adultInfo().angry(); + this.wildClientTextureAsset = internal.adultInfo().wild(); + this.tameClientTextureAsset = internal.adultInfo().tame(); + this.babyAngryClientTextureAsset = internal.babyInfo().angry(); + this.babyWildClientTextureAsset = internal.babyInfo().wild(); + this.babyTameClientTextureAsset = internal.babyInfo().tame(); this.spawnConditions = internal.spawnConditions(); } @@ -52,6 +58,21 @@ public ClientTextureAsset tameClientTextureAsset() { return this.conversions.asBukkit(asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset")); } + @Override + public ClientTextureAsset babyAngryClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyAngryClientTextureAsset, "babyAngryClientTextureAsset")); + } + + @Override + public ClientTextureAsset babyWildClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyWildClientTextureAsset, "babyWildClientTextureAsset")); + } + + @Override + public ClientTextureAsset babyTameClientTextureAsset() { + return this.conversions.asBukkit(asConfigured(this.babyTameClientTextureAsset, "babyTameClientTextureAsset")); + } + public static final class PaperBuilder extends PaperWolfVariantRegistryEntry implements Builder, PaperRegistryBuilder { public PaperBuilder(final Conversions conversions, final @Nullable WolfVariant internal) { @@ -76,6 +97,24 @@ public Builder tameClientTextureAsset(final ClientTextureAsset tameClientTexture return this; } + @Override + public Builder babyAngryClientTextureAsset(final ClientTextureAsset babyAngryClientTextureAsset) { + this.babyAngryClientTextureAsset = this.conversions.asVanilla(asArgument(babyAngryClientTextureAsset, "babyAngryClientTextureAsset")); + return this; + } + + @Override + public Builder babyWildClientTextureAsset(final ClientTextureAsset babyWildClientTextureAsset) { + this.babyWildClientTextureAsset = this.conversions.asVanilla(asArgument(babyWildClientTextureAsset, "babyWildClientTextureAsset")); + return this; + } + + @Override + public Builder babyTameClientTextureAsset(final ClientTextureAsset babyTameClientTextureAsset) { + this.babyTameClientTextureAsset = this.conversions.asVanilla(asArgument(babyTameClientTextureAsset, "babyTameClientTextureAsset")); + return this; + } + @Override public WolfVariant build() { return new WolfVariant( @@ -84,6 +123,11 @@ public WolfVariant build() { asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"), asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset") ), + new WolfVariant.AssetInfo( + asConfigured(this.babyWildClientTextureAsset, "babyWildClientTextureAsset"), + asConfigured(this.babyTameClientTextureAsset, "babyTameClientTextureAsset"), + asConfigured(this.babyAngryClientTextureAsset, "babyAngryClientTextureAsset") + ), asConfigured(this.spawnConditions, "spawnConditions") ); } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/dialog/PaperDialogCodecs.java b/paper-server/src/main/java/io/papermc/paper/registry/data/dialog/PaperDialogCodecs.java index 209ea05ade06..36af145550a2 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/dialog/PaperDialogCodecs.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/dialog/PaperDialogCodecs.java @@ -85,7 +85,7 @@ private PaperDialogCodecs() { ); private static final Codec SIMPLE_PLAIN_MESSAGE_BODY_CODEC = Codec.withAlternative(PLAIN_MESSAGE_BODY_CODEC.codec(), AdventureCodecs.COMPONENT_CODEC, component -> DialogBody.plainMessage(component, PlainMessage.DEFAULT_WIDTH)); private static final MapCodec ITEM_BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( - ItemStack.STRICT_CODEC.xmap(CraftItemStack::asBukkitCopy, CraftItemStack::asNMSCopy).fieldOf("item").forGetter(ItemDialogBody::item), + ItemStack.CODEC.xmap(CraftItemStack::asBukkitCopy, CraftItemStack::asNMSCopy).fieldOf("item").forGetter(ItemDialogBody::item), SIMPLE_PLAIN_MESSAGE_BODY_CODEC.optionalFieldOf("description").forGetter(body -> Optional.ofNullable(body.description())), Codec.BOOL.optionalFieldOf("show_decorations", true).forGetter(ItemDialogBody::showDecorations), Codec.BOOL.optionalFieldOf("show_tooltip", true).forGetter(ItemDialogBody::showTooltip), diff --git a/paper-server/src/main/java/io/papermc/paper/util/MappingEnvironment.java b/paper-server/src/main/java/io/papermc/paper/util/MappingEnvironment.java deleted file mode 100644 index a9363c43d9d4..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/util/MappingEnvironment.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.papermc.paper.util; - -import java.io.InputStream; -import java.util.Objects; -import java.util.jar.Manifest; -import net.minecraft.world.entity.MobCategory; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; - -@DefaultQualifier(NonNull.class) -public final class MappingEnvironment { - public static final boolean DISABLE_PLUGIN_REMAPPING = Boolean.getBoolean("paper.disablePluginRemapping"); - public static final String LEGACY_CB_VERSION = "v1_21_R7"; - private static final @Nullable String MAPPINGS_HASH = readMappingsHash(); - private static final boolean REOBF = checkReobf(); - - private MappingEnvironment() { - } - - public static boolean reobf() { - return REOBF; - } - - public static boolean hasMappings() { - return MAPPINGS_HASH != null; - } - - public static InputStream mappingsStream() { - return Objects.requireNonNull(mappingsStreamIfPresent(), "Missing mappings!"); - } - - public static @Nullable InputStream mappingsStreamIfPresent() { - return MappingEnvironment.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny"); - } - - public static String mappingsHash() { - return Objects.requireNonNull(MAPPINGS_HASH, "MAPPINGS_HASH"); - } - - private static @Nullable String readMappingsHash() { - final @Nullable Manifest manifest = JarManifests.manifest(MappingEnvironment.class); - if (manifest != null) { - final Object hash = manifest.getMainAttributes().getValue("Included-Mappings-Hash"); - if (hash != null) { - return hash.toString(); - } - } - - final @Nullable InputStream stream = mappingsStreamIfPresent(); - if (stream == null) { - return null; - } - return Hashing.sha256(stream); - } - - @SuppressWarnings("ConstantConditions") - private static boolean checkReobf() { - final Class clazz = MobCategory.class; - if (clazz.getSimpleName().equals("MobCategory")) { - return false; - } else if (clazz.getSimpleName().equals("EnumCreatureType")) { - return true; - } - throw new IllegalStateException(); - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/util/ObfHelper.java b/paper-server/src/main/java/io/papermc/paper/util/ObfHelper.java deleted file mode 100644 index 6067be951c4c..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/util/ObfHelper.java +++ /dev/null @@ -1,156 +0,0 @@ -package io.papermc.paper.util; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import net.neoforged.srgutils.IMappingFile; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.DefaultQualifier; - -@DefaultQualifier(NonNull.class) -public enum ObfHelper { - INSTANCE; - - private final @Nullable Map mappingsByObfName; - private final @Nullable Map mappingsByMojangName; - - ObfHelper() { - final @Nullable Set maps = loadMappingsIfPresent(); - if (maps != null) { - this.mappingsByObfName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::obfName, map -> map)); - this.mappingsByMojangName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::mojangName, map -> map)); - } else { - this.mappingsByObfName = null; - this.mappingsByMojangName = null; - } - } - - public @Nullable Map mappingsByObfName() { - return this.mappingsByObfName; - } - - public @Nullable Map mappingsByMojangName() { - return this.mappingsByMojangName; - } - - /** - * Attempts to get the obf name for a given class by its Mojang name. Will - * return the input string if mappings are not present. - * - * @param fullyQualifiedMojangName fully qualified class name (dotted) - * @return mapped or original fully qualified (dotted) class name - */ - public String reobfClassName(final String fullyQualifiedMojangName) { - if (this.mappingsByMojangName == null) { - return fullyQualifiedMojangName; - } - - final ClassMapping map = this.mappingsByMojangName.get(fullyQualifiedMojangName); - if (map == null) { - return fullyQualifiedMojangName; - } - - return map.obfName(); - } - - /** - * Attempts to get the Mojang name for a given class by its obf name. Will - * return the input string if mappings are not present. - * - * @param fullyQualifiedObfName fully qualified class name (dotted) - * @return mapped or original fully qualified (dotted) class name - */ - public String deobfClassName(final String fullyQualifiedObfName) { - if (this.mappingsByObfName == null) { - return fullyQualifiedObfName; - } - - final ClassMapping map = this.mappingsByObfName.get(fullyQualifiedObfName); - if (map == null) { - return fullyQualifiedObfName; - } - - return map.mojangName(); - } - - private static @Nullable Set loadMappingsIfPresent() { - if (!MappingEnvironment.hasMappings()) { - return null; - } - try (final InputStream mappingsInputStream = MappingEnvironment.mappingsStream()) { - final IMappingFile mappings = IMappingFile.load(mappingsInputStream); // Mappings are mojang->spigot - final Set classes = new HashSet<>(); - - final StringPool pool = new StringPool(); - for (final IMappingFile.IClass cls : mappings.getClasses()) { - final Map methods = new HashMap<>(); - final Map fields = new HashMap<>(); - final Map strippedMethods = new HashMap<>(); - - for (final IMappingFile.IMethod methodMapping : cls.getMethods()) { - methods.put( - pool.string(methodKey( - Objects.requireNonNull(methodMapping.getMapped()), - Objects.requireNonNull(methodMapping.getMappedDescriptor()) - )), - pool.string(Objects.requireNonNull(methodMapping.getOriginal())) - ); - - strippedMethods.put( - pool.string(pool.string(strippedMethodKey( - methodMapping.getMapped(), - methodMapping.getDescriptor() - ))), - pool.string(methodMapping.getOriginal()) - ); - } - for (final IMappingFile.IField field : cls.getFields()) { - fields.put( - pool.string(field.getMapped()), - pool.string(field.getOriginal()) - ); - } - - final ClassMapping map = new ClassMapping( - Objects.requireNonNull(cls.getMapped()).replace('/', '.'), - Objects.requireNonNull(cls.getOriginal()).replace('/', '.'), - Map.copyOf(methods), - Map.copyOf(fields), - Map.copyOf(strippedMethods) - ); - classes.add(map); - } - - return Set.copyOf(classes); - } catch (final IOException ex) { - System.err.println("Failed to load mappings."); - ex.printStackTrace(); - return null; - } - } - - public static String strippedMethodKey(final String methodName, final String methodDescriptor) { - final String methodKey = methodKey(methodName, methodDescriptor); - final int returnDescriptorEnd = methodKey.indexOf(')'); - return methodKey.substring(0, returnDescriptorEnd + 1); - } - - public static String methodKey(final String methodName, final String methodDescriptor) { - return methodName + methodDescriptor; - } - - public record ClassMapping( - String obfName, - String mojangName, - Map methodsByObf, - Map fieldsByObf, - // obf name with mapped desc to mapped name. return value is excluded from desc as reflection doesn't use it - Map strippedMethods - ) {} -} diff --git a/paper-server/src/main/java/io/papermc/paper/util/sanitizer/OversizedItemComponentSanitizer.java b/paper-server/src/main/java/io/papermc/paper/util/sanitizer/OversizedItemComponentSanitizer.java index 59f7e2c36d54..311b9fea0994 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/sanitizer/OversizedItemComponentSanitizer.java +++ b/paper-server/src/main/java/io/papermc/paper/util/sanitizer/OversizedItemComponentSanitizer.java @@ -12,6 +12,7 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemStackTemplate; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.BundleContents; import net.minecraft.world.item.component.ChargedProjectiles; @@ -59,12 +60,11 @@ private static ChargedProjectiles sanitizeChargedProjectiles(final ChargedProjec return projectiles; } - return ChargedProjectiles.of(List.of( - new ItemStack( - projectiles.contains(Items.FIREWORK_ROCKET) - ? Items.FIREWORK_ROCKET - : Items.ARROW - ))); + return ChargedProjectiles.of(ItemStackTemplate.fromNonEmptyStack(new ItemStack( + projectiles.contains(Items.FIREWORK_ROCKET) + ? Items.FIREWORK_ROCKET + : Items.ARROW + ))); } private static ItemContainerContents sanitizeItemContainerContents(final ItemContainerContents contents) { @@ -86,16 +86,16 @@ private static BundleContents sanitizeBundleContents(final BundleContents conten // A bundles content weight may be anywhere from 0 to, basically, infinity. // A weight of 1 is the usual maximum case - int sizeUsed = Mth.mulAndTruncate(contents.weight(), 64); + int sizeUsed = Mth.mulAndTruncate(contents.weight().getOrThrow(), 64); // Early out, *most* bundles should not be overfilled above a weight of one. if (sizeUsed <= 64) { - return new BundleContents(List.of(new ItemStack(Items.PAPER, Math.max(1, sizeUsed)))); + return new BundleContents(List.of(ItemStackTemplate.fromNonEmptyStack(new ItemStack(Items.PAPER, Math.max(1, sizeUsed))))); } - final List sanitizedRepresentation = new ObjectArrayList<>(sizeUsed / 64 + 1); + final List sanitizedRepresentation = new ObjectArrayList<>(sizeUsed / 64 + 1); while (sizeUsed > 0) { final int stackCount = Math.min(64, sizeUsed); - sanitizedRepresentation.add(new ItemStack(Items.PAPER, stackCount)); + sanitizedRepresentation.add(ItemStackTemplate.fromNonEmptyStack(new ItemStack(Items.PAPER, stackCount))); sizeUsed -= stackCount; } // Now we add a single fake item that uses the same amount of slots as all other items. diff --git a/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java b/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java index 51a01f86fee5..8e9ed8ca960e 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java +++ b/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java @@ -12,7 +12,9 @@ import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.worldupdate.UpgradeProgress; import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.storage.LevelDataAndDimensions; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelSummary; import net.minecraft.world.level.storage.PrimaryLevelData; @@ -129,9 +131,9 @@ public void loadInitialWorlds() { return; } - final PrimaryLevelData primaryLevelData; + final LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings; if (levelData.dataTag == null) { - primaryLevelData = (PrimaryLevelData) Main.createNewWorldData( + worldDataAndGenSettings = Main.createNewWorldData( ((DedicatedServer) this.server).settings, this.server.worldLoaderContext, this.server.worldLoaderContext.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM), @@ -139,21 +141,22 @@ public void loadInitialWorlds() { this.server.options.has("bonusChest") ).cookie(); } else { - primaryLevelData = (PrimaryLevelData) LevelStorageSource.getLevelDataAndDimensions( + worldDataAndGenSettings = LevelStorageSource.getLevelDataAndDimensions( + levelStorageAccess, levelData.dataTag, this.server.worldLoaderContext.dataConfiguration(), this.server.worldLoaderContext.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM), this.server.worldLoaderContext.datapackWorldgen() - ).worldData(); + ).worldDataAndGenSettings(); } + final var primaryLevelData = ((PrimaryLevelData) worldDataAndGenSettings.data()); primaryLevelData.checkName(info.name()); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end) primaryLevelData.setModdedInfo(this.server.getServerModName(), this.server.getModdedStatus().shouldReportAsModified()); if (this.server.options.has("forceUpgrade")) { Main.forceUpgrade( levelStorageAccess, - primaryLevelData, DataFixers.getDataFixer(), this.server.options.has("eraseCache"), () -> true, @@ -162,10 +165,10 @@ public void loadInitialWorlds() { ); } - this.server.createLevel(stem, info, levelStorageAccess, primaryLevelData); + this.server.createLevel(stem, info, levelStorageAccess, worldDataAndGenSettings); } - ((DedicatedServer) this.server).forceDifficulty(); + // ((DedicatedServer) this.server).forceDifficulty(); for (ServerLevel serverLevel : this.server.getAllLevels()) { this.server.prepareLevel(serverLevel); @@ -176,35 +179,19 @@ public record LevelDataResult(@Nullable Dynamic dataTag, boolean fatalError) // Based on code in net.minecraft.server.Main public static LevelDataResult getLevelData( - final LevelStorageSource.LevelStorageAccess levelStorageAccess + final LevelStorageSource.LevelStorageAccess access ) { - Dynamic dataTag; - if (levelStorageAccess.hasWorldData()) { - LevelSummary summary; + Dynamic levelDataTag; + if (access.hasWorldData()) { + Dynamic levelDataUnfixed; try { - dataTag = levelStorageAccess.getDataTag(); - summary = levelStorageAccess.getSummary(dataTag); - } catch (NbtException | ReportedNbtException | IOException var41) { - LevelStorageSource.LevelDirectory levelDirectory = levelStorageAccess.getLevelDirectory(); - LOGGER.warn("Failed to load world data from {}", levelDirectory.dataFile(), var41); - LOGGER.info("Attempting to use fallback"); - - try { - dataTag = levelStorageAccess.getDataTagFallback(); - summary = levelStorageAccess.getSummary(dataTag); - } catch (NbtException | ReportedNbtException | IOException var40) { - LOGGER.error("Failed to load world data from {}", levelDirectory.oldDataFile(), var40); - LOGGER.error( - "Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", - levelDirectory.dataFile(), - levelDirectory.oldDataFile() - ); - return new LevelDataResult(null, true); - } - - levelStorageAccess.restoreLevelDataFromOld(); + levelDataUnfixed = access.getUnfixedDataTagWithFallback(); + } catch (NbtException | ReportedNbtException | IOException var39) { + LOGGER.error("Failed to load world data. World files may be corrupted. Shutting down.", var39); + return new LevelDataResult(null, true); } + LevelSummary summary = access.fixAndGetSummaryFromTag(levelDataUnfixed); if (summary.requiresManualConversion()) { LOGGER.info("This world must be opened in an older version (like 1.6.4) to be safely converted"); return new LevelDataResult(null, true); @@ -214,10 +201,12 @@ public static LevelDataResult getLevelData( LOGGER.info("This world was created by an incompatible version."); return new LevelDataResult(null, true); } + + levelDataTag = DataFixers.getFileFixer().fix(access, levelDataUnfixed, new UpgradeProgress()); } else { return new LevelDataResult(null, false); } - return new LevelDataResult(dataTag, false); + return new LevelDataResult(levelDataTag, false); } } diff --git a/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java b/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java index c0953bb67dcf..0594a87cda7b 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java @@ -9,8 +9,6 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.flag.FeatureFlags; import org.bukkit.FeatureFlag; -import org.bukkit.GameRule; -import org.bukkit.craftbukkit.CraftGameRule; import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.potion.CraftPotionType; import org.bukkit.entity.EntityType; @@ -49,8 +47,6 @@ static FeatureElement getFeatureElement(final FeatureDependant dependant) { return CraftEntityType.bukkitToMinecraft(entityType); } else if (dependant instanceof final PotionType potionType) { return CraftPotionType.bukkitToMinecraft(potionType); - } else if (dependant instanceof final GameRule gameRule) { - return () -> CraftGameRule.bukkitToMinecraft(gameRule).requiredFeatures(); } else { throw new IllegalArgumentException(dependant + " is not a valid feature dependant"); } diff --git a/paper-server/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java b/paper-server/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java index 8fa41e9d4210..58d12afe9b03 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java +++ b/paper-server/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java @@ -69,7 +69,7 @@ protected boolean compute() { } else if (blockY >= falseAtAndAboveY) { return false; } else { - double d = Mth.map(blockY, trueAtAndBelowY, falseAtAndAboveY, 1.0D, 0.0D); + double d = Mth.map(blockY, trueAtAndBelowY, falseAtAndAboveY, 1.0, 0.0); RandomSource randomSource = positionalRandomFactory.at(this.context.blockX, blockY, this.context.blockZ); return (double)randomSource.nextFloat() < d; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index 09baa8c13a56..757080357da8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -54,8 +54,8 @@ public class CraftChunk implements Chunk { public CraftChunk(net.minecraft.world.level.chunk.LevelChunk chunk) { this.level = chunk.level; - this.x = chunk.getPos().x; - this.z = chunk.getPos().z; + this.x = chunk.getPos().x(); + this.z = chunk.getPos().z(); } public CraftChunk(ServerLevel level, int x, int z) { @@ -114,7 +114,7 @@ public Block getBlock(int x, int y, int z) { @Override public boolean isEntitiesLoaded() { - return this.getCraftWorld().getHandle().areEntitiesLoaded(ChunkPos.asLong(this.x, this.z)); // Paper - chunk system + return this.getCraftWorld().getHandle().areEntitiesLoaded(ChunkPos.pack(this.x, this.z)); // Paper - chunk system } @Override @@ -392,7 +392,7 @@ public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world empty[i] = true; if (biome != null) { - biome[i] = (PalettedContainer>) biomeCodec.parse(NbtOps.INSTANCE, biomeCodec.encodeStart(NbtOps.INSTANCE, actual.getSection(i).getBiomes()).getOrThrow()).getOrThrow(SerializableChunkData.ChunkReadException::new); + biome[i] = actual.getSection(i).getBiomes().copy(); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java index 251eb8dba549..00cf1caf9488 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java @@ -103,7 +103,7 @@ public Material getBlockType(int x, int y, int z) { public final BlockData getBlockData(int x, int y, int z) { this.validateChunkCoordinates(x, y, z); - return CraftBlockData.fromData(this.blockIds[this.getSectionIndex(y)].get(x, y & 0xF, z)); + return this.blockIds[this.getSectionIndex(y)].get(x, y & 0xF, z).asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftGameRule.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftGameRule.java index 5d42203a9079..57525b527ebd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftGameRule.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftGameRule.java @@ -1,7 +1,7 @@ package org.bukkit.craftbukkit; import com.mojang.serialization.DataResult; -import io.papermc.paper.util.Holderable; +import io.papermc.paper.world.flag.PaperFeatureDependent; import java.util.function.BiFunction; import java.util.function.Function; import net.minecraft.core.Holder; @@ -11,7 +11,7 @@ import org.jspecify.annotations.NullMarked; @NullMarked -public class CraftGameRule extends GameRule implements Holderable> { +public class CraftGameRule extends GameRule implements PaperFeatureDependent> { public static final BiFunction, IllegalArgumentException> INVALID_VALUE = (value, error) -> { return new IllegalArgumentException("Invalid value: %s (%s)".formatted(value, error.message())); @@ -44,22 +44,22 @@ public Holder> getHolder() { @Override public NamespacedKey getKey() { - return Holderable.super.getKey(); + return PaperFeatureDependent.super.getKey(); } @Override public int hashCode() { - return Holderable.super.implHashCode(); + return PaperFeatureDependent.super.implHashCode(); } @Override public boolean equals(final Object obj) { - return Holderable.super.implEquals(obj); + return PaperFeatureDependent.super.implEquals(obj); } @Override public String toString() { - return Holderable.super.implToString(); + return PaperFeatureDependent.super.implToString(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java index 3f940a89a336..9ce08bbb3a8b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftParticle.java @@ -82,7 +82,7 @@ public static ParticleOptions createParticleParam(Particle particle, D data) public static T convertLegacy(T object) { if (object instanceof MaterialData mat) { - return (T) CraftBlockData.fromData(CraftMagicNumbers.getBlock(mat)); + return (T) CraftMagicNumbers.getBlock(mat).asBlockData(); } return object; @@ -132,7 +132,7 @@ public ParticleOptions createParticleParam(Particle.DustOptions data) { BiFunction, CraftParticle> itemStackFunction = (name, particle) -> new CraftParticle<>(name, particle, ItemStack.class) { @Override public ParticleOptions createParticleParam(ItemStack data) { - return new ItemParticleOption((net.minecraft.core.particles.ParticleType) this.getHandle(), CraftItemStack.asNMSCopy(data)); + return new ItemParticleOption((net.minecraft.core.particles.ParticleType) this.getHandle(), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(data))); } }; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 21d594a39d09..b98a2d09f802 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -15,15 +15,16 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; +import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.level.Level; +import net.minecraft.world.level.MoonPhase; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.ChorusFlowerBlock; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; -import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.phys.Vec3; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.RegionAccessor; @@ -99,7 +100,7 @@ public io.papermc.paper.block.fluid.FluidData getFluidData(final int x, final in @Override public BlockData getBlockData(int x, int y, int z) { - return CraftBlockData.fromData(this.getData(x, y, z)); + return this.getData(x, y, z).asBlockData(); } @Override @@ -466,7 +467,8 @@ public net.minecraft.world.entity.Entity createEntity(Location location, Class Mth.square(128D)) { + if (end.distanceToSqr(start) > Mth.square(128.0)) { return false; // Return early if the distance is greater than 128 blocks } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index da49c8005592..1a424833da89 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -95,7 +95,6 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.RepairItemRecipe; import net.minecraft.world.level.CustomSpawner; -import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.BiomeManager; @@ -104,14 +103,17 @@ import net.minecraft.world.level.levelgen.PatrolSpawner; import net.minecraft.world.level.levelgen.PhantomSpawner; import net.minecraft.world.level.levelgen.WorldDimensions; +import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.minecraft.world.level.storage.LevelDataAndDimensions; +import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PlayerDataStorage; import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.level.storage.SavedDataStorage; import net.minecraft.world.level.validation.ContentValidationException; import org.apache.commons.lang3.StringUtils; import org.bukkit.BanList; @@ -780,7 +782,7 @@ public String getWorldType() { @Override public boolean getGenerateStructures() { - return this.getServer().getWorldData().worldGenOptions().generateStructures(); + return this.getServer().getWorldGenSettings().options().generateStructures(); } @Override @@ -1053,7 +1055,6 @@ public void reload() { this.enablePlugins(PluginLoadOrder.STARTUP); this.enablePlugins(PluginLoadOrder.POSTWORLD); this.spark.registerCommandAfterPlugins(this); // Paper - spark - if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins // Paper start - brigadier command API io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // to clear invalid state for event fire below io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // call commands event for regular plugins @@ -1221,16 +1222,16 @@ public World createWorld(WorldCreator creator) { boolean hardcore = creator.hardcore(); - PrimaryLevelData primaryLevelData; + LevelDataAndDimensions.WorldDataAndGenSettings worldDataAndGenSettings; WorldLoader.DataLoadContext context = this.console.worldLoaderContext; RegistryAccess.Frozen registryAccess = context.datapackDimensions(); net.minecraft.core.Registry contextLevelStemRegistry = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); Dynamic dataTag = PaperWorldLoader.getLevelData(levelStorageAccess).dataTag(); if (dataTag != null) { LevelDataAndDimensions levelDataAndDimensions = LevelStorageSource.getLevelDataAndDimensions( - dataTag, context.dataConfiguration(), contextLevelStemRegistry, context.datapackWorldgen() + levelStorageAccess, dataTag, context.dataConfiguration(), contextLevelStemRegistry, context.datapackWorldgen() ); - primaryLevelData = (PrimaryLevelData) levelDataAndDimensions.worldData(); + worldDataAndGenSettings = levelDataAndDimensions.worldDataAndGenSettings(); registryAccess = levelDataAndDimensions.dimensions().dimensionsRegistryAccess(); } else { LevelSettings levelSettings; @@ -1241,9 +1242,8 @@ public World createWorld(WorldCreator creator) { levelSettings = new LevelSettings( name, GameType.byId(this.getDefaultGameMode().getValue()), - hardcore, Difficulty.EASY, + new LevelSettings.DifficultySettings(Difficulty.EASY, hardcore, false), false, - new GameRules(context.dataConfiguration().enabledFeatures()), context.dataConfiguration() ); worldDimensions = properties.create(context.datapackWorldgen()); @@ -1251,26 +1251,26 @@ public World createWorld(WorldCreator creator) { WorldDimensions.Complete complete = worldDimensions.bake(contextLevelStemRegistry); Lifecycle lifecycle = complete.lifecycle().add(context.datapackWorldgen().allRegistriesLifecycle()); - primaryLevelData = new PrimaryLevelData(levelSettings, worldOptions, complete.specialWorldProperty(), lifecycle); + worldDataAndGenSettings = new LevelDataAndDimensions.WorldDataAndGenSettings( + new PrimaryLevelData(levelSettings, complete.specialWorldProperty(), lifecycle), + new WorldGenSettings(worldOptions, worldDimensions) + ); registryAccess = complete.dimensionsRegistryAccess(); } + final PrimaryLevelData primaryLevelData = (PrimaryLevelData) worldDataAndGenSettings.data(); contextLevelStemRegistry = registryAccess.lookupOrThrow(Registries.LEVEL_STEM); - primaryLevelData.customDimensions = contextLevelStemRegistry; primaryLevelData.checkName(name); primaryLevelData.setModdedInfo(this.console.getServerModName(), this.console.getModdedStatus().shouldReportAsModified()); if (this.console.options.has("forceUpgrade")) { - net.minecraft.server.Main.forceUpgrade(levelStorageAccess, primaryLevelData, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, registryAccess, this.console.options.has("recreateRegionFiles")); + net.minecraft.server.Main.forceUpgrade(levelStorageAccess, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, registryAccess, this.console.options.has("recreateRegionFiles")); } - long i = BiomeManager.obfuscateSeed(primaryLevelData.worldGenOptions().seed()); - List list = ImmutableList.of( - new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(primaryLevelData) - ); + long biomeZoomSeed = BiomeManager.obfuscateSeed(worldDataAndGenSettings.genSettings().options().seed()); LevelStem customStem = contextLevelStemRegistry.getValue(actualDimension); - WorldInfo worldInfo = new CraftWorldInfo(primaryLevelData, levelStorageAccess, creator.environment(), customStem.type().value(), customStem.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo + WorldInfo worldInfo = new CraftWorldInfo(worldDataAndGenSettings, levelStorageAccess, creator.environment(), customStem.type().value(), customStem.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo if (biomeProvider == null && chunkGenerator != null) { biomeProvider = chunkGenerator.getDefaultBiomeProvider(worldInfo); } @@ -1285,20 +1285,27 @@ public World createWorld(WorldCreator creator) { dimensionKey = ResourceKey.create(Registries.DIMENSION, Identifier.fromNamespaceAndPath(creator.key().namespace(), creator.key().value())); } + final SavedDataStorage savedDataStorage = new SavedDataStorage(levelStorageAccess.getLevelPath(LevelResource.DATA), this.console.getFixerUpper(), this.console.registryAccess()); + savedDataStorage.set(WorldGenSettings.TYPE, worldDataAndGenSettings.genSettings()); + List list = ImmutableList.of( + new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(savedDataStorage) + ); + ServerLevel serverLevel = new ServerLevel( this.console, this.console.executor, levelStorageAccess, - primaryLevelData, + worldDataAndGenSettings, dimensionKey, customStem, primaryLevelData.isDebugWorld(), - i, + biomeZoomSeed, creator.environment() == Environment.NORMAL ? list : ImmutableList.of(), true, - this.console.overworld().getRandomSequences(), creator.environment(), - chunkGenerator, biomeProvider + chunkGenerator, + biomeProvider, + savedDataStorage ); if (!(this.worlds.containsKey(name.toLowerCase(Locale.ROOT)))) { @@ -1306,7 +1313,7 @@ public World createWorld(WorldCreator creator) { } this.console.addLevel(serverLevel); // Paper - Put world into worldlist before initing the world; move up - this.console.initWorld(serverLevel, primaryLevelData, primaryLevelData.worldGenOptions()); + this.console.initWorld(serverLevel); serverLevel.setSpawnSettings(true); // Paper - Put world into worldlist before initing the world; move up @@ -1559,7 +1566,7 @@ public ItemCraftResult craftItemResult(ItemStack[] craftingMatrix, World world, RecipeHolder recipeCrafting = recipe.get(); craftingContainer.setCurrentRecipe(recipeCrafting); if (craftResult.setRecipeUsed(craftPlayer.getHandle(), recipeCrafting)) { - itemstack = recipeCrafting.value().assemble(craftingContainer.asCraftInput(), craftWorld.getHandle().registryAccess()); + itemstack = recipeCrafting.value().assemble(craftingContainer.asCraftInput()); } } @@ -1584,7 +1591,7 @@ public ItemCraftResult craftItemResult(ItemStack[] craftingMatrix, World world) net.minecraft.world.item.ItemStack itemStack = net.minecraft.world.item.ItemStack.EMPTY; if (recipe.isPresent()) { - itemStack = recipe.get().value().assemble(craftingContainer.asCraftInput(), craftWorld.getHandle().registryAccess()); + itemStack = recipe.get().value().assemble(craftingContainer.asCraftInput()); } return this.createItemCraftResult(recipe, CraftItemStack.asBukkitCopy(itemStack), craftingContainer); @@ -2180,7 +2187,7 @@ public WorldMetadataStore getWorldMetadata() { @Override public File getWorldContainer() { - return this.getServer().storageSource.getDimensionPath(net.minecraft.world.level.Level.OVERWORLD).getParent().toFile(); + return this.getServer().storageSource.getLevelDirectory().path().getParent().toFile(); } @Override @@ -2441,7 +2448,7 @@ public KeyedBossBar createBossBar(NamespacedKey key, String title, BarColor barC Preconditions.checkArgument(barColor != null, "BarColor key cannot be null"); Preconditions.checkArgument(barStyle != null, "BarStyle key cannot be null"); - CustomBossEvent bossBattleCustom = this.getServer().getCustomBossEvents().create(CraftNamespacedKey.toMinecraft(key), CraftChatMessage.fromString(title, true)[0]); + CustomBossEvent bossBattleCustom = this.getServer().getCustomBossEvents().create(net.minecraft.util.RandomSource.create(), CraftNamespacedKey.toMinecraft(key), CraftChatMessage.fromString(title, true)[0]); CraftKeyedBossbar craftKeyedBossbar = new CraftKeyedBossbar(bossBattleCustom); craftKeyedBossbar.setColor(barColor); craftKeyedBossbar.setStyle(barStyle); @@ -2547,7 +2554,7 @@ public BlockData createBlockData(org.bukkit.Material material, String data) { Preconditions.checkArgument(type != null, "Provided material must be a block"); } - return CraftBlockData.newData(type, data); + return CraftBlockData.fromString(type, data); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index ebc65e3338c6..b96c0781ce0e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -40,7 +40,6 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; -import net.minecraft.network.protocol.game.ClientboundSetTimePacket; import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.resources.Identifier; @@ -74,7 +73,6 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.gamerules.GameRule; -import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.LevelResource; @@ -89,6 +87,7 @@ import org.bukkit.Difficulty; import org.bukkit.Effect; import org.bukkit.FluidCollisionMode; +import org.bukkit.GameRules; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.Particle; @@ -138,6 +137,8 @@ import org.bukkit.entity.Trident; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.weather.LightningStrikeEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.world.TimeSkipEvent; import org.bukkit.generator.BiomeProvider; @@ -475,7 +476,7 @@ private boolean unloadChunk0(int x, int z, boolean save) { @Override public boolean refreshChunk(int x, int z) { - ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); + ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.pack(x, z)); if (playerChunk == null) return false; // Paper start - chunk system @@ -619,7 +620,7 @@ public Collection getIntersectingChunks(@NotNull BoundingBox boundingBox) @Override public boolean isChunkForceLoaded(int x, int z) { - return this.getHandle().getForceLoadedChunks().contains(ChunkPos.asLong(x, z)); + return this.getHandle().getForceLoadedChunks().contains(ChunkPos.pack(x, z)); } @Override @@ -663,9 +664,9 @@ public org.bukkit.entity.Item dropItemNaturally(Location location, ItemStack ite Preconditions.checkArgument(location != null, "Location cannot be null"); Preconditions.checkArgument(item != null, "ItemStack cannot be null"); - double xs = Mth.nextDouble(this.world.random, -0.25D, 0.25D); - double ys = Mth.nextDouble(this.world.random, -0.25D, 0.25D) - ((double) EntityType.ITEM.getHeight() / 2.0D); - double zs = Mth.nextDouble(this.world.random, -0.25D, 0.25D); + double xs = Mth.nextDouble(this.world.getRandom(), -0.25, 0.25); + double ys = Mth.nextDouble(this.world.getRandom(), -0.25, 0.25) - ((double) EntityType.ITEM.getHeight() / 2.0); + double zs = Mth.nextDouble(this.world.getRandom(), -0.25, 0.25); location = location.clone().add(xs, ys, zs); return this.dropItem(location, item, function); } @@ -796,27 +797,24 @@ public void setTime(long time) { @Override public long getFullTime() { - return this.world.getDayTime(); + return this.world.getDefaultClockTime(); } @Override public void setFullTime(long time) { - // Notify anyone who's listening - TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - this.world.getDayTime()); + if (this.world.dimensionType().defaultClock().isEmpty()) { + throw new IllegalArgumentException("Cannot set time in world without world clock"); + } + + final long currentClockTime = this.world.getDefaultClockTime(); + final TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - currentClockTime); this.server.getPluginManager().callEvent(event); if (event.isCancelled()) { return; } - this.world.setDayTime(this.world.getDayTime() + event.getSkipAmount()); - - // Forces the client to update to the new time immediately - for (Player p : this.getPlayers()) { - CraftPlayer cp = (CraftPlayer) p; - if (cp.getHandle().connection == null) continue; - - cp.getHandle().connection.send(new ClientboundSetTimePacket(cp.getHandle().level().getGameTime(), cp.getHandle().getPlayerTime(), cp.getHandle().relativeTime && cp.getHandle().level().getGameRules().get(GameRules.ADVANCE_TIME))); - } + // Updates the clock for all players + this.world.clockManager().setTotalTicks(this.world.dimensionType().defaultClock().get(), currentClockTime + event.getSkipAmount()); } // Paper start @@ -992,7 +990,7 @@ public RayTraceResult rayTraceEntities(io.papermc.paper.math.Position start, Vec Preconditions.checkArgument(direction.lengthSquared() > 0, "Direction's magnitude (%s) need to be greater than 0", direction.lengthSquared()); - if (maxDistance < 0.0D) { + if (maxDistance < 0.0) { return null; } @@ -1040,7 +1038,7 @@ public RayTraceResult rayTraceBlocks(io.papermc.paper.math.Position start, Vecto Preconditions.checkArgument(fluidCollisionMode != null, "FluidCollisionMode cannot be null"); Preconditions.checkArgument(blockCollisionMode != null, "BlockCollisionMode cannot be null"); - if (maxDistance < 0.0D) { + if (maxDistance < 0.0) { return null; } @@ -1178,46 +1176,46 @@ public BlockMetadataStore getBlockMetadata() { @Override public boolean hasStorm() { - return this.world.levelData.isRaining(); + return this.world.getWeatherData().isRaining(); } @Override public void setStorm(boolean hasStorm) { - this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.world.getWeatherData().setRaining(hasStorm, WeatherChangeEvent.Cause.PLUGIN); this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) } @Override public int getWeatherDuration() { - return this.world.serverLevelData.getRainTime(); + return this.world.getWeatherData().getRainTime(); } @Override public void setWeatherDuration(int duration) { - this.world.serverLevelData.setRainTime(duration); + this.world.getWeatherData().setRainTime(duration); } @Override public boolean isThundering() { - return this.world.levelData.isThundering(); + return this.world.getWeatherData().isThundering(); } @Override public void setThundering(boolean thundering) { - this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.world.getWeatherData().setThundering(thundering, ThunderChangeEvent.Cause.PLUGIN); this.setThunderDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) } @Override public int getThunderDuration() { - return this.world.serverLevelData.getThunderTime(); + return this.world.getWeatherData().getThunderTime(); } @Override public void setThunderDuration(int duration) { - this.world.serverLevelData.setThunderTime(duration); + this.world.getWeatherData().setThunderTime(duration); } @Override @@ -1227,12 +1225,12 @@ public boolean isClearWeather() { @Override public void setClearWeatherDuration(int duration) { - this.world.serverLevelData.setClearWeatherTime(duration); + this.world.getWeatherData().setClearWeatherTime(duration); } @Override public int getClearWeatherDuration() { - return this.world.serverLevelData.getClearWeatherTime(); + return this.world.getWeatherData().getClearWeatherTime(); } @Override @@ -1247,7 +1245,7 @@ public boolean getPVP() { @Override public void setPVP(boolean pvp) { - this.world.getGameRules().set(GameRules.PVP, pvp, this.world); + this.setGameRule(GameRules.PVP, pvp); } @Override @@ -1458,12 +1456,12 @@ public org.bukkit.WorldType getWorldType() { @Override public boolean canGenerateStructures() { - return this.world.serverLevelData.worldGenOptions().generateStructures(); + return this.world.worldDataAndGenSettings.genSettings().options().generateStructures(); } @Override public boolean hasBonusChest() { - return this.world.serverLevelData.worldGenOptions().generateBonusChest(); + return this.world.worldDataAndGenSettings.genSettings().options().generateBonusChest(); } @Override @@ -1473,7 +1471,7 @@ public boolean isHardcore() { @Override public void setHardcore(boolean hardcore) { - this.world.serverLevelData.settings.hardcore = hardcore; + this.world.serverLevelData.settings = this.world.serverLevelData.settings.withHardcore(hardcore); } @Override @@ -1538,12 +1536,12 @@ public void setSpawnLimit(SpawnCategory spawnCategory, int limit) { @Override public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch) { - this.playSound(loc, sound, category, volume, pitch, this.getHandle().random.nextLong()); + this.playSound(loc, sound, category, volume, pitch, this.getHandle().getRandom().nextLong()); } @Override public void playSound(Location loc, String sound, org.bukkit.SoundCategory category, float volume, float pitch) { - this.playSound(loc, sound, category, volume, pitch, this.getHandle().random.nextLong()); + this.playSound(loc, sound, category, volume, pitch, this.getHandle().getRandom().nextLong()); } @Override @@ -1568,17 +1566,17 @@ public void playSound(Location loc, String sound, org.bukkit.SoundCategory categ double z = loc.getZ(); ClientboundSoundPacket packet = new ClientboundSoundPacket(Holder.direct(SoundEvent.createVariableRangeEvent(Identifier.parse(sound))), SoundSource.valueOf(category.name()), x, y, z, volume, pitch, seed); - this.world.getServer().getPlayerList().broadcast(null, x, y, z, volume > 1.0F ? 16.0F * volume : 16.0D, this.world.dimension(), packet); + this.world.getServer().getPlayerList().broadcast(null, x, y, z, volume > 1.0F ? 16.0F * volume : 16.0, this.world.dimension(), packet); } @Override public void playSound(Entity entity, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch) { - this.playSound(entity, sound, category, volume, pitch, this.getHandle().random.nextLong()); + this.playSound(entity, sound, category, volume, pitch, this.getHandle().getRandom().nextLong()); } @Override public void playSound(Entity entity, String sound, org.bukkit.SoundCategory category, float volume, float pitch) { - this.playSound(entity, sound, category, volume, pitch, this.getHandle().random.nextLong()); + this.playSound(entity, sound, category, volume, pitch, this.getHandle().getRandom().nextLong()); } @Override @@ -1770,7 +1768,7 @@ public void spawnParticle(Particle particle, List receivers, Player force, false, x, y, z, // Position - count, // Count + count, // Count offsetX, offsetY, offsetZ, // Random offset extra // Speed? ); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorldBorder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorldBorder.java index e52f412d01cf..70d4be7ce9ac 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorldBorder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorldBorder.java @@ -38,14 +38,14 @@ public double getSize() { @Override public void setSize(double newSize) { - Preconditions.checkArgument(newSize >= 1.0D && newSize <= this.getMaxSize(), "newSize must be between 1.0D and %s", this.getMaxSize()); + Preconditions.checkArgument(newSize >= 1.0 && newSize <= this.getMaxSize(), "newSize must be between 1.0 and %s", this.getMaxSize()); this.handle.setSize(newSize); } @Override public void changeSize(double newSize, long ticks) { Preconditions.checkArgument(ticks >= 0 && ticks <= Integer.MAX_VALUE, "ticks must be between 0-%s", Integer.MAX_VALUE); - Preconditions.checkArgument(newSize >= 1.0D && newSize <= this.getMaxSize(), "newSize must be between 1.0D and %s", this.getMaxSize()); + Preconditions.checkArgument(newSize >= 1.0 && newSize <= this.getMaxSize(), "newSize must be between 1.0 and %s", this.getMaxSize()); if (ticks > 0L) { final long startTime = (this.getWorld() != null) ? this.getWorld().getGameTime() : 0; // Virtual Borders don't have a World diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java b/paper-server/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java index fc6c5bd8f43f..ff717cb38e6d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java @@ -31,7 +31,7 @@ public String getDescription() { @Override public ItemStack getIcon() { - return CraftItemStack.asBukkitCopy(this.handle.getIcon()); + return CraftItemStack.asBukkitCopy(this.handle.getIcon().create()); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java index f3673c0cc1a8..cc6e8b25f864 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java @@ -33,7 +33,7 @@ protected CraftBanner(CraftBanner state, Location location) { public void load(BannerBlockEntity blockEntity) { super.load(blockEntity); - this.base = DyeColor.getByWoolData((byte) ((AbstractBannerBlock) this.data.getBlock()).getColor().getId()); + this.base = DyeColor.getByWoolData((byte) ((AbstractBannerBlock) this.block.getBlock()).getColor().getId()); this.patterns = new ArrayList<>(); for (int i = 0; i < blockEntity.getPatterns().layers().size(); i++) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java index 687311a9224d..4c08d9d6af8d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java @@ -7,6 +7,7 @@ import net.minecraft.advancements.criterion.DataComponentMatchers; import net.minecraft.advancements.criterion.ItemPredicate; import net.minecraft.advancements.criterion.MinMaxBounds; +import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentExactPredicate; import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; @@ -111,7 +112,9 @@ public boolean isLocked() { @Override public String getLock() { - Optional customName = this.getSnapshot().lockKey.predicate().components().exact().asPatch().get(DataComponents.CUSTOM_NAME); + Optional customName = Optional.ofNullable( + this.getSnapshot().lockKey.predicate().components().exact().asPatch().get(DataComponentMap.EMPTY, DataComponents.CUSTOM_NAME) + ); return (customName != null) ? customName.map(CraftChatMessage::fromComponent).orElse("") : ""; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 31e665388bc6..ccc34f6e0264 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -17,9 +17,13 @@ import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.SignalGetter; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LevelEvent; import net.minecraft.world.level.block.RedStoneWireBlock; import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.Redstone; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; @@ -36,7 +40,6 @@ import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; import org.bukkit.block.PistonMoveReaction; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftFluidCollisionMode; @@ -60,39 +63,36 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jspecify.annotations.Nullable; public class CraftBlock implements Block { - private final net.minecraft.world.level.LevelAccessor world; + private final net.minecraft.world.level.LevelAccessor level; private final BlockPos position; - private CraftBlock(LevelAccessor world, BlockPos position) { - this.world = world; + private CraftBlock(LevelAccessor level, BlockPos position) { + this.level = level; this.position = position.immutable(); } - public static CraftBlock at(LevelAccessor world, BlockPos position) { - return new CraftBlock(world, position); + public static CraftBlock at(LevelAccessor level, BlockPos position) { + return new CraftBlock(level, position); } - public net.minecraft.world.level.block.state.BlockState getNMS() { - return this.world.getBlockState(this.position); - } - - public net.minecraft.world.level.material.FluidState getNMSFluid() { - return this.world.getFluidState(this.position); + public net.minecraft.world.level.block.state.BlockState getBlockState() { + return this.level.getBlockState(this.position); } public BlockPos getPosition() { return this.position; } - public LevelAccessor getHandle() { - return this.world; + public LevelAccessor getLevel() { + return this.level; } @Override public World getWorld() { - return this.world.getMinecraftWorld().getWorld(); + return this.level.getMinecraftWorld().getWorld(); } public CraftWorld getCraftWorld() { @@ -111,8 +111,7 @@ public Location getLocation(Location loc) { loc.setX(this.position.getX()); loc.setY(this.position.getY()); loc.setZ(this.position.getZ()); - loc.setYaw(0); - loc.setPitch(0); + loc.setRotation(0, 0); } return loc; @@ -147,26 +146,21 @@ public void setData(final byte data) { } public void setData(final byte data, boolean applyPhysics) { - if (applyPhysics) { - this.setData(data, net.minecraft.world.level.block.Block.UPDATE_ALL); - } else { - this.setData(data, net.minecraft.world.level.block.Block.UPDATE_CLIENTS); - } + this.setData(data, net.minecraft.world.level.block.Block.UPDATE_CLIENTS | (applyPhysics ? net.minecraft.world.level.block.Block.UPDATE_NEIGHBORS : 0)); } private void setData(final byte data, @net.minecraft.world.level.block.Block.UpdateFlags int flags) { - this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flags); + this.level.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flags); } @Override public byte getData() { - net.minecraft.world.level.block.state.BlockState state = this.world.getBlockState(this.position); - return CraftMagicNumbers.toLegacyData(state); + return CraftMagicNumbers.toLegacyData(this.getBlockState()); } @Override public BlockData getBlockData() { - return CraftBlockData.fromData(this.getNMS()); + return this.getBlockState().asBlockData(); } @Override @@ -192,7 +186,7 @@ public void setBlockData(BlockData data, boolean applyPhysics) { } boolean setBlockState(final net.minecraft.world.level.block.state.BlockState state, final boolean applyPhysics) { - return CraftBlock.setBlockState(this.world, this.position, this.getNMS(), state, applyPhysics); + return setBlockState(this.level, this.position, this.getBlockState(), state, applyPhysics); } public static boolean setBlockState(LevelAccessor world, BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, boolean applyPhysics) { @@ -227,30 +221,22 @@ public static boolean setBlockState(LevelAccessor world, BlockPos pos, net.minec @Override public Material getType() { - return this.world.getBlockState(this.position).getBukkitMaterial(); // Paper - optimise getType calls + return this.getBlockState().getBukkitMaterial(); } @Override public byte getLightLevel() { - return (byte) this.world.getMinecraftWorld().getMaxLocalRawBrightness(this.position); + return (byte) this.level.getMinecraftWorld().getMaxLocalRawBrightness(this.position); } @Override public byte getLightFromSky() { - return (byte) this.world.getBrightness(LightLayer.SKY, this.position); + return (byte) this.level.getBrightness(LightLayer.SKY, this.position); } @Override public byte getLightFromBlocks() { - return (byte) this.world.getBrightness(LightLayer.BLOCK, this.position); - } - - public Block getFace(final BlockFace face) { - return this.getRelative(face, 1); - } - - public Block getFace(final BlockFace face, final int distance) { - return this.getRelative(face, distance); + return (byte) this.level.getBrightness(LightLayer.BLOCK, this.position); } @Override @@ -283,76 +269,53 @@ public BlockFace getFace(final Block block) { @Override public String toString() { - return "CraftBlock{pos=" + this.position + ",type=" + this.getType() + ",data=" + this.getNMS() + ",fluid=" + this.getNMSFluid() + '}'; + net.minecraft.world.level.block.state.BlockState state = this.getBlockState(); + return "CraftBlock{pos=" + this.position + ", type=" + this.getType() + ", data=" + state + ", fluid=" + state.getFluidState() + '}'; } - public static BlockFace notchToBlockFace(Direction notch) { - if (notch == null) { - return BlockFace.SELF; - } - switch (notch) { - case DOWN: - return BlockFace.DOWN; - case UP: - return BlockFace.UP; - case NORTH: - return BlockFace.NORTH; - case SOUTH: - return BlockFace.SOUTH; - case WEST: - return BlockFace.WEST; - case EAST: - return BlockFace.EAST; - default: - return BlockFace.SELF; - } + public static BlockFace notchToBlockFace(@Nullable Direction direction) { + return switch (direction) { + case DOWN -> BlockFace.DOWN; + case UP -> BlockFace.UP; + case NORTH -> BlockFace.NORTH; + case SOUTH -> BlockFace.SOUTH; + case WEST -> BlockFace.WEST; + case EAST -> BlockFace.EAST; + case null -> BlockFace.SELF; + }; } - public static Direction blockFaceToNotch(BlockFace face) { - if (face == null) { - return null; - } - switch (face) { - case DOWN: - return Direction.DOWN; - case UP: - return Direction.UP; - case NORTH: - return Direction.NORTH; - case SOUTH: - return Direction.SOUTH; - case WEST: - return Direction.WEST; - case EAST: - return Direction.EAST; - default: - return null; - } + public static @Nullable Direction blockFaceToNotch(@Nullable BlockFace face) { + return switch (face) { + case DOWN -> Direction.DOWN; + case UP -> Direction.UP; + case NORTH -> Direction.NORTH; + case SOUTH -> Direction.SOUTH; + case WEST -> Direction.WEST; + case EAST -> Direction.EAST; + case null, default -> null; + }; } @Override - public BlockState getState() { + public org.bukkit.block.BlockState getState() { return CraftBlockStates.getBlockState(this); } - // Paper start @Override - public BlockState getState(boolean useSnapshot) { + public org.bukkit.block.BlockState getState(boolean useSnapshot) { return CraftBlockStates.getBlockState(this, useSnapshot); } - // Paper end @Override public Biome getBiome() { return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); } - // Paper start @Override public Biome getComputedBiome() { return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); } - // Paper end @Override public void setBiome(Biome bio) { @@ -361,7 +324,7 @@ public void setBiome(Biome bio) { @Override public double getTemperature() { - return this.world.getBiome(this.position).value().getTemperature(this.position, this.world.getSeaLevel()); + return this.level.getBiome(this.position).value().getTemperature(this.position, this.level.getSeaLevel()); } @Override @@ -371,12 +334,12 @@ public double getHumidity() { @Override public boolean isBlockPowered() { - return this.world.getMinecraftWorld().getDirectSignalTo(this.position) > 0; + return this.level.getMinecraftWorld().getDirectSignalTo(this.position) > Redstone.SIGNAL_MIN; } @Override public boolean isBlockIndirectlyPowered() { - return this.world.getMinecraftWorld().hasNeighborSignal(this.position); + return this.level.getMinecraftWorld().hasNeighborSignal(this.position); } @Override @@ -398,87 +361,98 @@ public int hashCode() { @Override public boolean isBlockFacePowered(BlockFace face) { - return this.world.getMinecraftWorld().hasSignal(this.position, CraftBlock.blockFaceToNotch(face)); + Direction direction = blockFaceToNotch(face); + Preconditions.checkArgument(direction != null, face + " is not a valid cartesian face"); + return this.level.getMinecraftWorld().hasSignal(this.position, direction); } @Override public boolean isBlockFaceIndirectlyPowered(BlockFace face) { - int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face)); + Direction direction = blockFaceToNotch(face); + Preconditions.checkArgument(direction != null, face + " is not a valid cartesian face"); + if (this.level.getMinecraftWorld().hasSignal(this.position, direction)) { + return true; + } - Block relative = this.getRelative(face); - if (relative.getType() == Material.REDSTONE_WIRE) { - return Math.max(power, relative.getData()) > 0; // todo remove legacy usage + BlockState neighborState = this.level.getBlockState(this.position.relative(direction)); + if (neighborState.hasProperty(RedStoneWireBlock.POWER)) { + return neighborState.getValue(RedStoneWireBlock.POWER) > Redstone.SIGNAL_MIN; } - return power > 0; + return false; } @Override public int getBlockPower(BlockFace face) { - int power = 0; - net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); - int x = this.getX(); - int y = this.getY(); - int z = this.getZ(); - if ((face == BlockFace.DOWN || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x, y - 1, z), Direction.DOWN)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x, y - 1, z))); - if ((face == BlockFace.UP || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x, y + 1, z), Direction.UP)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x, y + 1, z))); - if ((face == BlockFace.EAST || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x + 1, y, z), Direction.EAST)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x + 1, y, z))); - if ((face == BlockFace.WEST || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x - 1, y, z), Direction.WEST)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x - 1, y, z))); - if ((face == BlockFace.NORTH || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x, y, z - 1), Direction.NORTH)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x, y, z - 1))); - if ((face == BlockFace.SOUTH || face == BlockFace.SELF) && world.hasSignal(new BlockPos(x, y, z + 1), Direction.SOUTH)) power = CraftBlock.getPower(power, world.getBlockState(new BlockPos(x, y, z + 1))); - return power > 0 ? power : (face == BlockFace.SELF ? this.isBlockIndirectlyPowered() : this.isBlockFaceIndirectlyPowered(face)) ? 15 : 0; - } - - private static int getPower(int power, net.minecraft.world.level.block.state.BlockState state) { - if (!state.is(Blocks.REDSTONE_WIRE)) { + Preconditions.checkArgument(face != null, "face cannot be null"); + + net.minecraft.world.level.Level level = this.level.getMinecraftWorld(); + boolean searchSelfIncluded = face == BlockFace.SELF; + Direction onlyFace = blockFaceToNotch(face); + + int power = Redstone.SIGNAL_NONE; + for (Direction direction : SignalGetter.DIRECTIONS) { + if (!searchSelfIncluded && direction != onlyFace) { + continue; + } + + BlockPos neighborPos = this.position.relative(direction); + if (level.hasSignal(neighborPos, direction)) { + BlockState state = level.getBlockState(neighborPos); + if (state.hasProperty(RedStoneWireBlock.POWER)) { + power = Math.max(state.getValue(RedStoneWireBlock.POWER), power); + if (power == Redstone.SIGNAL_MAX) { + return power; + } + } + } + } + + if (power != Redstone.SIGNAL_NONE) { return power; - } else { - return Math.max(state.getValue(RedStoneWireBlock.POWER), power); } - } - @Override - public int getBlockPower() { - return this.getBlockPower(BlockFace.SELF); + if (searchSelfIncluded) { + return this.isBlockIndirectlyPowered() ? Redstone.SIGNAL_MAX : Redstone.SIGNAL_MIN; + } + return this.isBlockFaceIndirectlyPowered(face) ? Redstone.SIGNAL_MAX : Redstone.SIGNAL_MIN; } @Override public boolean isEmpty() { - return this.getNMS().isAir(); + return this.getBlockState().isAir(); } @Override public boolean isLiquid() { - return this.getNMS().liquid(); + return this.getBlockState().liquid(); } - // Paper start @Override public boolean isBuildable() { - return this.getNMS().isSolid(); // This is in fact isSolid, despite the fact that isSolid below returns blocksMotion + return this.getBlockState().isSolid(); // This is in fact isSolid, despite the fact that isSolid below returns blocksMotion } @Override public boolean isBurnable() { - return this.getNMS().ignitedByLava(); + return this.getBlockState().ignitedByLava(); } @Override public boolean isReplaceable() { - return this.getNMS().canBeReplaced(); + return this.getBlockState().canBeReplaced(); } @Override public boolean isSolid() { - return this.getNMS().blocksMotion(); + return this.getBlockState().blocksMotion(); } @Override public boolean isCollidable() { - return getNMS().getBlock().hasCollision; + return getBlockState().getBlock().hasCollision; } - // Paper end @Override public PistonMoveReaction getPistonMoveReaction() { - return PistonMoveReaction.getById(this.getNMS().getPistonPushReaction().ordinal()); + return PistonMoveReaction.getById(this.getBlockState().getPistonPushReaction().ordinal()); } @Override @@ -488,7 +462,6 @@ public boolean breakNaturally() { @Override public boolean breakNaturally(ItemStack item) { - // Paper start return this.breakNaturally(item, false); } @@ -504,51 +477,47 @@ public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dro @Override public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dropExperience, boolean forceEffect) { - // Paper end // Order matters here, need to drop before setting to air so skulls can get their data - net.minecraft.world.level.block.state.BlockState state = this.getNMS(); + BlockState state = this.getBlockState(); net.minecraft.world.level.block.Block block = state.getBlock(); net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); boolean result = false; // Modelled off Player#hasCorrectToolForDrops - if (block != Blocks.AIR && (item == null || !state.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(state))) { - net.minecraft.world.level.block.Block.dropResources(state, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem, false); // Paper - Properly handle xp dropping - // Paper start - improve Block#breakNaturally - if (dropExperience) block.popExperience(this.world.getMinecraftWorld(), this.position, block.getExpDrop(state, this.world.getMinecraftWorld(), this.position, nmsItem, true)); - // Paper end + if (!state.isAir() && (item == null || !state.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(state))) { + net.minecraft.world.level.block.Block.dropResources(state, this.level.getMinecraftWorld(), this.position, this.level.getBlockEntity(this.position), null, nmsItem, false); + if (dropExperience) block.popExperience(this.level.getMinecraftWorld(), this.position, block.getExpDrop(state, this.level.getMinecraftWorld(), this.position, nmsItem, true)); result = true; } - if ((result && triggerEffect) || (forceEffect && block != Blocks.AIR)) { - if (state.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) { - this.world.levelEvent(net.minecraft.world.level.block.LevelEvent.SOUND_EXTINGUISH_FIRE, this.position, 0); + if ((result && triggerEffect) || (forceEffect && !state.isAir())) { + if (block instanceof net.minecraft.world.level.block.BaseFireBlock) { + this.level.levelEvent(LevelEvent.SOUND_EXTINGUISH_FIRE, this.position, 0); } else { - this.world.levelEvent(net.minecraft.world.level.block.LevelEvent.PARTICLES_DESTROY_BLOCK, this.position, net.minecraft.world.level.block.Block.getId(state)); + this.level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, this.position, net.minecraft.world.level.block.Block.getId(state)); } } - // SPIGOT-6778: Directly call setBlock instead of setBlockState, so that the block entity is not removed and custom remove logic is run. - // Paper start - improve breakNaturally - boolean destroyed = this.world.removeBlock(this.position, false); + boolean destroyed = this.level.removeBlock(this.position, false); if (destroyed) { - block.destroy(this.world, this.position, state); + block.destroy(this.level, this.position, state); } if (result) { // special cases if (block instanceof net.minecraft.world.level.block.IceBlock iceBlock) { - iceBlock.afterDestroy(this.world.getMinecraftWorld(), this.position, nmsItem); + iceBlock.afterDestroy(this.level.getMinecraftWorld(), this.position, nmsItem); } else if (block instanceof net.minecraft.world.level.block.TurtleEggBlock turtleEggBlock) { - turtleEggBlock.decreaseEggs(this.world.getMinecraftWorld(), this.position, state); + turtleEggBlock.decreaseEggs(this.level.getMinecraftWorld(), this.position, state); } } return destroyed && result; - // Paper end } @Override public boolean applyBoneMeal(BlockFace face) { - Direction direction = CraftBlock.blockFaceToNotch(face); + Direction direction = blockFaceToNotch(face); + Preconditions.checkArgument(direction != null, face + " is not a valid cartesian face"); + BlockFertilizeEvent event = null; ServerLevel world = this.getCraftWorld().getHandle(); UseOnContext context = new UseOnContext(world, null, InteractionHand.MAIN_HAND, Items.BONE_MEAL.getDefaultInstance(), new BlockHitResult(Vec3.ZERO, direction, this.getPosition(), false)); @@ -561,7 +530,7 @@ public boolean applyBoneMeal(BlockFace face) { if (!world.capturedBlockStates.isEmpty()) { TreeType treeType = SaplingBlock.treeType; SaplingBlock.treeType = null; - List states = new ArrayList<>(world.capturedBlockStates.values()); + List states = new ArrayList<>(world.capturedBlockStates.values()); world.capturedBlockStates.clear(); StructureGrowEvent structureEvent = null; @@ -575,10 +544,10 @@ public boolean applyBoneMeal(BlockFace face) { Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled()) { - for (BlockState state : states) { + for (org.bukkit.block.BlockState state : states) { CraftBlockState craftBlockState = (CraftBlockState) state; craftBlockState.place(craftBlockState.getFlags()); - world.checkCapturedTreeStateForObserverNotify(this.position, craftBlockState); // Paper - notify observers even if grow failed + world.checkCapturedTreeStateForObserverNotify(this.position, craftBlockState); } } } @@ -598,12 +567,12 @@ public Collection getDrops(ItemStack item) { @Override public Collection getDrops(ItemStack item, Entity entity) { - net.minecraft.world.level.block.state.BlockState state = this.getNMS(); + BlockState state = this.getBlockState(); net.minecraft.world.item.ItemStack nms = CraftItemStack.asNMSCopy(item); // Modelled off Player#hasCorrectToolForDrops if (item == null || CraftBlockData.isPreferredTool(state, nms)) { - return net.minecraft.world.level.block.Block.getDrops(state, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), entity == null ? null : ((CraftEntity) entity).getHandle(), nms) + return net.minecraft.world.level.block.Block.getDrops(state, this.level.getMinecraftWorld(), this.position, this.level.getBlockEntity(this.position), entity == null ? null : ((CraftEntity) entity).getHandle(), nms) .stream().map(CraftItemStack::asBukkitCopy).collect(Collectors.toList()); } else { return Collections.emptyList(); @@ -612,15 +581,13 @@ public Collection getDrops(ItemStack item, Entity entity) { @Override public boolean isPreferredTool(ItemStack item) { - net.minecraft.world.level.block.state.BlockState state = this.getNMS(); - net.minecraft.world.item.ItemStack nms = CraftItemStack.asNMSCopy(item); - return CraftBlockData.isPreferredTool(state, nms); + return CraftBlockData.isPreferredTool(this.getBlockState(), CraftItemStack.asNMSCopy(item)); } @Override public float getBreakSpeed(Player player) { Preconditions.checkArgument(player != null, "player cannot be null"); - return this.getNMS().getDestroyProgress(((CraftPlayer) player).getHandle(), this.world, this.position); + return this.getBlockState().getDestroyProgress(((CraftPlayer) player).getHandle(), this.level, this.position); } @Override @@ -645,7 +612,7 @@ public void removeMetadata(String metadataKey, Plugin owningPlugin) { @Override public boolean isPassable() { - return this.getNMS().getCollisionShape(this.world, this.position).isEmpty(); + return this.getBlockState().getCollisionShape(this.level, this.position).isEmpty(); } @Override @@ -659,7 +626,7 @@ public RayTraceResult rayTrace(Location start, Vector direction, double maxDista Preconditions.checkArgument(direction.lengthSquared() > 0, "Direction's magnitude (%s) must be greater than 0", direction.lengthSquared()); Preconditions.checkArgument(fluidCollisionMode != null, "FluidCollisionMode cannot be null"); - if (maxDistance < 0.0D) { + if (maxDistance < 0.0) { return null; } @@ -667,13 +634,13 @@ public RayTraceResult rayTrace(Location start, Vector direction, double maxDista Vec3 startPos = CraftLocation.toVec3(start); Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ()); - HitResult hitResult = this.world.clip(new ClipContext(startPos, endPos, ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toFluid(fluidCollisionMode), CollisionContext.empty()), this.position); - return CraftRayTraceResult.convertFromInternal(this.world, hitResult); + HitResult hitResult = this.level.clip(new ClipContext(startPos, endPos, ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toFluid(fluidCollisionMode), CollisionContext.empty()), this.position); + return CraftRayTraceResult.convertFromInternal(this.level, hitResult); } @Override public BoundingBox getBoundingBox() { - VoxelShape shape = this.getNMS().getShape(this.world, this.position); + VoxelShape shape = this.getBlockState().getShape(this.level, this.position); if (shape.isEmpty()) { return new BoundingBox(); // Return an empty bounding box if the block has no dimension @@ -685,65 +652,62 @@ public BoundingBox getBoundingBox() { @Override public org.bukkit.util.VoxelShape getCollisionShape() { - VoxelShape shape = this.getNMS().getCollisionShape(this.world, this.position); + VoxelShape shape = this.getBlockState().getCollisionShape(this.level, this.position); return new CraftVoxelShape(shape); } @Override public boolean canPlace(BlockData data) { Preconditions.checkArgument(data != null, "BlockData cannot be null"); - net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState(); - net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); - return iblockdata.canSurvive(world, this.position); + BlockState state = ((CraftBlockData) data).getState(); + return state.canSurvive(this.level.getMinecraftWorld(), this.position); } @Override public String getTranslationKey() { - return this.getNMS().getBlock().getDescriptionId(); + return this.getBlockState().getBlock().getDescriptionId(); } @Override public boolean isSuffocating() { - return this.getNMS().isSuffocating(this.world, this.position); + return this.getBlockState().isSuffocating(this.level, this.position); } - // Paper start @Override public com.destroystokyo.paper.block.BlockSoundGroup getSoundGroup() { - return new com.destroystokyo.paper.block.CraftBlockSoundGroup(getNMS().getBlock().defaultBlockState().getSoundType()); + return new com.destroystokyo.paper.block.CraftBlockSoundGroup(this.getBlockState().getSoundType()); } @Override public org.bukkit.SoundGroup getBlockSoundGroup() { - return org.bukkit.craftbukkit.CraftSoundGroup.getSoundGroup(this.getNMS().getSoundType()); + return org.bukkit.craftbukkit.CraftSoundGroup.getSoundGroup(this.getBlockState().getSoundType()); } @Override public String translationKey() { - return this.getNMS().getBlock().getDescriptionId(); + return this.getBlockState().getBlock().getDescriptionId(); } - public boolean isValidTool(ItemStack itemStack) { - return getDrops(itemStack).size() != 0; + public boolean isValidTool(ItemStack tool) { + return !this.getDrops(tool).isEmpty(); } @Override public void tick() { - final ServerLevel level = this.world.getMinecraftWorld(); - this.getNMS().tick(level, this.position, level.random); + final ServerLevel level = this.level.getMinecraftWorld(); + this.getBlockState().tick(level, this.position, level.getRandom()); } @Override public void fluidTick() { - this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position, this.getNMS()); + this.level.getFluidState(this.position).tick(this.level.getMinecraftWorld(), this.position, this.getBlockState()); } @Override public void randomTick() { - final ServerLevel level = this.world.getMinecraftWorld(); - this.getNMS().randomTick(level, this.position, level.random); + final ServerLevel level = this.level.getMinecraftWorld(); + this.getBlockState().randomTick(level, this.position, level.getRandom()); } - // Paper end } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java index 3036f3fa8b58..b246b4464598 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java @@ -27,16 +27,16 @@ public class CraftBlockState implements BlockState { protected final CraftWorld world; private final BlockPos position; - protected net.minecraft.world.level.block.state.BlockState data; + protected net.minecraft.world.level.block.state.BlockState block; @net.minecraft.world.level.block.Block.UpdateFlags protected int capturedFlags; // todo move out of this class - private WeakReference weakWorld; + private WeakReference weakLevel; protected CraftBlockState(final Block block) { - this(block.getWorld(), ((CraftBlock) block).getPosition(), ((CraftBlock) block).getNMS()); + this(block.getWorld(), ((CraftBlock) block).getPosition(), ((CraftBlock) block).getBlockState()); this.capturedFlags = net.minecraft.world.level.block.Block.UPDATE_ALL; - this.setWorldHandle(((CraftBlock) block).getHandle()); + this.setWorldHandle(((CraftBlock) block).getLevel()); } @Deprecated @@ -46,54 +46,54 @@ protected CraftBlockState(final Block block, @net.minecraft.world.level.block.Bl } // world can be null for non-placed BlockStates. - protected CraftBlockState(@Nullable World world, BlockPos pos, net.minecraft.world.level.block.state.BlockState data) { + protected CraftBlockState(@Nullable World world, BlockPos pos, net.minecraft.world.level.block.state.BlockState block) { this.world = (CraftWorld) world; this.position = pos; - this.data = data; + this.block = block; } // Creates an unplaced copy of the given CraftBlockState at the given location - protected CraftBlockState(CraftBlockState state, @Nullable Location location) { + protected CraftBlockState(CraftBlockState from, @Nullable Location location) { if (location == null) { this.world = null; - this.position = state.getPosition().immutable(); + this.position = from.getPosition().immutable(); } else { this.world = (CraftWorld) location.getWorld(); this.position = CraftLocation.toBlockPosition(location); } - this.data = state.data; - this.capturedFlags = state.capturedFlags; - this.setWorldHandle(state.getWorldHandle()); + this.block = from.block; + this.capturedFlags = from.capturedFlags; + this.setWorldHandle(from.getWorldHandle()); } - public void setWorldHandle(LevelAccessor generatorAccess) { - if (generatorAccess instanceof net.minecraft.world.level.Level) { - this.weakWorld = null; + public void setWorldHandle(LevelAccessor level) { + if (level instanceof net.minecraft.world.level.Level) { + this.weakLevel = null; } else { - this.weakWorld = new WeakReference<>(generatorAccess); + this.weakLevel = new WeakReference<>(level); } } - // Returns null if weakWorld is not available and the BlockState is not placed. - // If this returns a World instead of only a GeneratorAccess, this implies that this BlockState is placed. + // Returns null if weakLevel is not available and the BlockState is not placed. + // If this returns a Level instead of only a LevelAccessor, this implies that this BlockState is placed. @Nullable public LevelAccessor getWorldHandle() { - if (this.weakWorld == null) { + if (this.weakLevel == null) { return this.isPlaced() ? this.world.getHandle() : null; } - LevelAccessor access = this.weakWorld.get(); - if (access == null) { - this.weakWorld = null; + LevelAccessor level = this.weakLevel.get(); + if (level == null) { + this.weakLevel = null; return this.isPlaced() ? this.world.getHandle() : null; } - return access; + return level; } protected final boolean isWorldGeneration() { - LevelAccessor generatorAccess = this.getWorldHandle(); - return generatorAccess != null && !(generatorAccess instanceof net.minecraft.world.level.Level); + LevelAccessor level = this.getWorldHandle(); + return level != null && !(level instanceof net.minecraft.world.level.Level); } protected final void ensureNoWorldGeneration() { @@ -127,8 +127,8 @@ public Chunk getChunk() { return this.world.getChunkAt(this.getX() >> 4, this.getZ() >> 4); } - public void setData(net.minecraft.world.level.block.state.BlockState data) { - this.data = data; + public void setBlock(net.minecraft.world.level.block.state.BlockState block) { + this.block = block; } public BlockPos getPosition() { @@ -136,35 +136,34 @@ public BlockPos getPosition() { } public net.minecraft.world.level.block.state.BlockState getHandle() { - return this.data; + return this.block; } @Override public BlockData getBlockData() { - return CraftBlockData.fromData(this.data); + return this.block.asBlockData(); } @Override public void setBlockData(BlockData data) { + // todo this is weird for block entities since the old methods are still available but not the new might be better to have wither Preconditions.checkArgument(data != null, "BlockData cannot be null"); - this.data = ((CraftBlockData) data).getState(); + this.block = ((CraftBlockData) data).getState(); } @Override public void setData(final MaterialData data) { - Material mat = CraftMagicNumbers.getMaterial(this.data).getItemType(); + Material mat = CraftMagicNumbers.getMaterial(this.block).getItemType(); - if ((mat == null) || (mat.getData() == null)) { - this.data = CraftMagicNumbers.getBlock(data); - } else { + if (mat != null) { Preconditions.checkArgument((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class), "Provided data is not of type %s, found %s", mat.getData().getName(), data.getClass().getName()); - this.data = CraftMagicNumbers.getBlock(data); } + this.block = CraftMagicNumbers.getBlock(data); } @Override public MaterialData getData() { - return CraftMagicNumbers.getMaterial(this.data); + return CraftMagicNumbers.getMaterial(this.block); } @Override @@ -173,13 +172,13 @@ public void setType(final Material type) { Preconditions.checkArgument(type.isBlock(), "Material must be a block!"); if (this.getType() != type) { - this.data = CraftBlockType.bukkitToMinecraft(type).defaultBlockState(); + this.block = CraftBlockType.bukkitToMinecraft(type).defaultBlockState(); } } @Override public Material getType() { - return this.data.getBukkitMaterial(); + return this.block.getBukkitMaterial(); } public void setFlags(@net.minecraft.world.level.block.Block.UpdateFlags int flags) { @@ -225,12 +224,12 @@ public boolean update(boolean force, boolean applyPhysics) { } } - net.minecraft.world.level.block.state.BlockState newBlock = this.data; + net.minecraft.world.level.block.state.BlockState newBlock = this.block; block.setBlockState(newBlock, applyPhysics); if (access instanceof net.minecraft.world.level.Level) { this.world.getHandle().sendBlockUpdated( this.position, - block.getNMS(), + block.getBlockState(), newBlock, net.minecraft.world.level.block.Block.UPDATE_ALL ); @@ -250,7 +249,7 @@ public boolean place(@net.minecraft.world.level.block.Block.UpdateFlags int flag return false; } - return this.getWorldHandle().setBlock(this.position, this.data, flags); + return this.getWorldHandle().setBlock(this.position, this.block, flags); } // used to revert a block placement due to an event being cancelled for example @@ -266,7 +265,7 @@ public boolean revertPlace() { @Override public byte getRawData() { - return CraftMagicNumbers.toLegacyData(this.data); + return CraftMagicNumbers.toLegacyData(this.block); } @Override @@ -281,8 +280,7 @@ public Location getLocation(Location loc) { loc.setX(this.getX()); loc.setY(this.getY()); loc.setZ(this.getZ()); - loc.setYaw(0); - loc.setPitch(0); + loc.setRotation(0, 0); } return loc; @@ -290,21 +288,19 @@ public Location getLocation(Location loc) { @Override public void setRawData(byte data) { - this.data = CraftMagicNumbers.getBlock(this.getType(), data); + this.block = CraftMagicNumbers.getBlock(this.getType(), data); } @Override public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (this.getClass() != obj.getClass()) { + if (obj == null || this.getClass() != obj.getClass()) { return false; } + final CraftBlockState other = (CraftBlockState) obj; return Objects.equals(this.world, other.world) && Objects.equals(this.position, other.position) && - Objects.equals(this.data, other.data); + Objects.equals(this.block, other.block); } @Override @@ -312,7 +308,7 @@ public int hashCode() { int hash = 7; hash = 73 * hash + (this.world != null ? this.world.hashCode() : 0); hash = 73 * hash + (this.position != null ? this.position.hashCode() : 0); - hash = 73 * hash + (this.data != null ? this.data.hashCode() : 0); + hash = 73 * hash + (this.block != null ? this.block.hashCode() : 0); return hash; } @@ -361,22 +357,22 @@ public BlockState copy(Location location) { @Override public boolean isCollidable() { - return this.data.getBlock().hasCollision; + return this.block.getBlock().hasCollision; } @Override - public java.util.Collection getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { + public java.util.Collection getDrops(org.bukkit.inventory.ItemStack tool, org.bukkit.entity.Entity entity) { this.requirePlaced(); - net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); + net.minecraft.world.item.ItemStack item = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(tool); // Modelled off Player#hasCorrectToolForDrops - if (item == null || !data.requiresCorrectToolForDrops() || nms.isCorrectToolForDrops(this.data)) { + if (tool == null || !this.block.requiresCorrectToolForDrops() || item.isCorrectToolForDrops(this.block)) { return net.minecraft.world.level.block.Block.getDrops( - this.data, + this.block, this.world.getHandle(), this.position, this.world.getHandle().getBlockEntity(this.position), entity == null ? null : - ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle(), nms + ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle(), item ).stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asBukkitCopy).toList(); } else { return java.util.Collections.emptyList(); @@ -386,6 +382,6 @@ public java.util.Collection getDrops(org.bukkit. @Override public boolean isSuffocating() { this.requirePlaced(); - return this.data.isSuffocating(this.getWorldHandle(), this.position); + return this.block.isSuffocating(this.getWorldHandle(), this.position); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java index bcd73c788768..42e6e246ed36 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java @@ -194,13 +194,13 @@ public static BlockState getBlockState(Block block, boolean useSnapshot) { CraftBlock craftBlock = (CraftBlock) block; CraftWorld world = (CraftWorld) block.getWorld(); BlockPos pos = craftBlock.getPosition(); - net.minecraft.world.level.block.state.BlockState state = craftBlock.getNMS(); - BlockEntity blockEntity = craftBlock.getHandle().getBlockEntity(pos); + net.minecraft.world.level.block.state.BlockState state = craftBlock.getBlockState(); + BlockEntity blockEntity = craftBlock.getLevel().getBlockEntity(pos); boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT; CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot; try { CraftBlockState blockState = CraftBlockStates.getBlockState(world, pos, state, blockEntity); - blockState.setWorldHandle(craftBlock.getHandle()); // Inject the block's generator access + blockState.setWorldHandle(craftBlock.getLevel()); // Inject the block's level accessor return blockState; } finally { CraftBlockEntityState.DISABLE_SNAPSHOT = prev; @@ -218,8 +218,8 @@ public static BlockState getBlockState(LevelReader world, BlockPos pos, Material public static BlockState getBlockState(RegistryAccess registry, BlockPos pos, Material material, @Nullable CompoundTag blockEntityTag) { Preconditions.checkNotNull(material, "material is null"); - net.minecraft.world.level.block.state.BlockState blockData = CraftBlockType.bukkitToMinecraft(material).defaultBlockState(); - return CraftBlockStates.getBlockState(registry, pos, blockData, blockEntityTag); + net.minecraft.world.level.block.state.BlockState state = CraftBlockType.bukkitToMinecraft(material).defaultBlockState(); + return CraftBlockStates.getBlockState(registry, pos, state, blockEntityTag); } @Deprecated diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockSupport.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockSupport.java index 5d902c1dfad7..a11e8eb3f113 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockSupport.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockSupport.java @@ -13,16 +13,14 @@ public static BlockSupport toBukkit(SupportType support) { case FULL -> BlockSupport.FULL; case CENTER -> BlockSupport.CENTER; case RIGID -> BlockSupport.RIGID; - default -> throw new IllegalArgumentException("Unsupported EnumBlockSupport type: " + support + ". This is a bug."); }; } - public static SupportType toNMS(BlockSupport support) { + public static SupportType toMinecraft(BlockSupport support) { return switch (support) { case FULL -> SupportType.FULL; case CENTER -> SupportType.CENTER; case RIGID -> SupportType.RIGID; - default -> throw new IllegalArgumentException("Unsupported BlockSupport type: " + support + ". This is a bug."); }; } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java index ace48e7b45e1..78744b74d7a0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockType.java @@ -99,7 +99,7 @@ private static boolean isInteractable(Block block) { @SuppressWarnings("unchecked") public CraftBlockType(final Holder holder) { super(holder); - this.blockDataClass = Suppliers.memoize(() -> (Class) CraftBlockData.fromData(this.getHandle().defaultBlockState()).getClass().getInterfaces()[0]); + this.blockDataClass = Suppliers.memoize(() -> (Class) this.getHandle().defaultBlockState().asBlockData().getClass().getInterfaces()[0]); this.interactable = Suppliers.memoize(() -> CraftBlockType.isInteractable(this.getHandle())); } @@ -150,7 +150,7 @@ public Collection createBlockDataStates() { final ImmutableList possibleStates = this.getHandle().getStateDefinition().getPossibleStates(); final ImmutableList.Builder builder = ImmutableList.builderWithExpectedSize(possibleStates.size()); for (final BlockState possibleState : possibleStates) { - builder.add(this.blockDataClass.get().cast(possibleState.createCraftBlockData())); + builder.add(this.blockDataClass.get().cast(possibleState.asBlockData())); } return builder.build(); } @@ -169,7 +169,7 @@ public B createBlockData(final @Nullable Consumer consumer) { @SuppressWarnings("unchecked") @Override public B createBlockData(final @Nullable String data) { - return (B) CraftBlockData.newData(this, data); + return (B) CraftBlockData.fromString(this, data); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java index f05ef791e4c1..6026bfb90047 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java @@ -1,8 +1,12 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.world.MenuProvider; +import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.DoubleBlockCombiner; import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Location; @@ -46,11 +50,11 @@ public Inventory getInventory() { CraftWorld world = (CraftWorld) this.getWorld(); - ChestBlock block = this.data.getBlock() instanceof ChestBlock chestBlock ? chestBlock : (ChestBlock) Blocks.CHEST; - MenuProvider provider = block.getMenuProvider(this.data, world.getHandle(), this.getPosition(), true); + ChestBlock block = this.block.getBlock() instanceof ChestBlock chestBlock ? chestBlock : (ChestBlock) Blocks.CHEST; + MenuProvider provider = block.getMenuProvider(this.block, world.getHandle(), this.getPosition(), true); - if (provider instanceof ChestBlock.DoubleInventory) { - inventory = new CraftInventoryDoubleChest((ChestBlock.DoubleInventory) provider); + if (provider instanceof ChestBlock.DoubleInventory doubleInventory) { + inventory = new CraftInventoryDoubleChest(doubleInventory); } return inventory; } @@ -58,12 +62,12 @@ public Inventory getInventory() { @Override public void open() { this.requirePlaced(); - if (!this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { + if (!this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level level) { BlockState block = this.getBlockEntity().getBlockState(); int openCount = this.getBlockEntity().openersCounter.getOpenerCount(); - this.getBlockEntity().openersCounter.onAPIOpen((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block); - this.getBlockEntity().openersCounter.openerAPICountChanged((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block, openCount, openCount + 1); + this.getBlockEntity().openersCounter.onOpenAPI(level, this.getPosition(), block); + this.getBlockEntity().openersCounter.openerCountChangedAPI(level, this.getPosition(), block, openCount, openCount + 1); } this.getBlockEntity().openersCounter.opened = true; } @@ -71,55 +75,52 @@ public void open() { @Override public void close() { this.requirePlaced(); - if (this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { + if (this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level level) { BlockState block = this.getBlockEntity().getBlockState(); int openCount = this.getBlockEntity().openersCounter.getOpenerCount(); - this.getBlockEntity().openersCounter.onAPIClose((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block); - this.getBlockEntity().openersCounter.openerAPICountChanged((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block, openCount, 0); + this.getBlockEntity().openersCounter.onCloseAPI(level, this.getPosition(), block); + this.getBlockEntity().openersCounter.openerCountChangedAPI(level, this.getPosition(), block, openCount, 0); } this.getBlockEntity().openersCounter.opened = false; } - @Override - public CraftChest copy() { - return new CraftChest(this, null); - } - - @Override - public CraftChest copy(Location location) { - return new CraftChest(this, location); - } - - // Paper start - More Lidded Block API @Override public boolean isOpen() { - return getBlockEntity().openersCounter.opened; + return this.getBlockEntity().openersCounter.opened; } - // Paper end - More Lidded Block API - // Paper start - More Chest Block API @Override public boolean isBlocked() { // Method mimics vanilla logic in ChestBlock and DoubleBlockCombiner when trying to open chest's container if (!isPlaced()) { return false; } - net.minecraft.world.level.LevelAccessor world = getWorldHandle(); - if (ChestBlock.isChestBlockedAt(world, getPosition())) { + + LevelAccessor level = this.getWorldHandle(); + if (ChestBlock.isChestBlockedAt(level, this.getPosition())) { return true; } - if (ChestBlock.getBlockType(this.data) == net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE) { + if (ChestBlock.getBlockType(this.block) == DoubleBlockCombiner.BlockType.SINGLE) { return false; } - net.minecraft.core.Direction direction = ChestBlock.getConnectedDirection(this.data); - net.minecraft.core.BlockPos neighbourBlockPos = getPosition().relative(direction); - BlockState neighbourBlockState = world.getBlockStateIfLoaded(neighbourBlockPos); - return neighbourBlockState != null - && neighbourBlockState.is(this.data.getBlock()) - && ChestBlock.getBlockType(neighbourBlockState) != net.minecraft.world.level.block.DoubleBlockCombiner.BlockType.SINGLE - && ChestBlock.getConnectedDirection(neighbourBlockState) == direction.getOpposite() - && ChestBlock.isChestBlockedAt(world, neighbourBlockPos); + Direction direction = ChestBlock.getConnectedDirection(this.block); + BlockPos neighborPos = this.getPosition().relative(direction); + BlockState neighborState = level.getBlockStateIfLoaded(neighborPos); + return neighborState != null + && neighborState.is(this.block.getBlock()) + && ChestBlock.getBlockType(neighborState) != DoubleBlockCombiner.BlockType.SINGLE + && ChestBlock.getConnectedDirection(neighborState) == direction.getOpposite() + && ChestBlock.isChestBlockedAt(level, neighborPos); + } + + @Override + public CraftChest copy() { + return new CraftChest(this, null); + } + + @Override + public CraftChest copy(Location location) { + return new CraftChest(this, location); } - // Paper end - More Chest Block API } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java index 1c448bc38fa5..eb7840449c03 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.Collection; -import net.minecraft.Optionull; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.EntityReference; import net.minecraft.world.level.block.entity.ConduitBlockEntity; @@ -104,7 +103,7 @@ public boolean setTarget(LivingEntity target) { ConduitBlockEntity.updateAndAttackTarget( conduit.getLevel().getMinecraftWorld(), this.getPosition(), - this.data, + this.block, conduit, conduit.effectBlocks.size() >= ConduitBlockEntity.MIN_KILL_SIZE, false diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java index 075921649b8a..598254bcc287 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java @@ -5,6 +5,7 @@ import net.minecraft.advancements.criterion.DataComponentMatchers; import net.minecraft.advancements.criterion.ItemPredicate; import net.minecraft.advancements.criterion.MinMaxBounds; +import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentExactPredicate; import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; @@ -34,7 +35,9 @@ public boolean isLocked() { @Override public String getLock() { - Optional customName = this.getSnapshot().lockKey.predicate().components().exact().asPatch().get(DataComponents.CUSTOM_NAME); + Optional customName = Optional.ofNullable( + this.getSnapshot().lockKey.predicate().components().exact().asPatch().get(DataComponentMap.EMPTY, DataComponents.CUSTOM_NAME) + ); return (customName != null) ? customName.map(CraftChatMessage::fromComponent).orElse("") : ""; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java index cb2a78e6ca51..2a9243e416bb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.EnderChestBlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Location; @@ -19,12 +20,12 @@ protected CraftEnderChest(CraftEnderChest state, Location location) { @Override public void open() { this.requirePlaced(); - if (!this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { + if (!this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level level) { BlockState block = this.getBlockEntity().getBlockState(); int openCount = this.getBlockEntity().openersCounter.getOpenerCount(); - this.getBlockEntity().openersCounter.onAPIOpen((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block); - this.getBlockEntity().openersCounter.openerAPICountChanged((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block, openCount, openCount + 1); + this.getBlockEntity().openersCounter.onOpenAPI(level, this.getPosition(), block); + this.getBlockEntity().openersCounter.openerCountChangedAPI(level, this.getPosition(), block, openCount, openCount + 1); } this.getBlockEntity().openersCounter.opened = true; } @@ -32,39 +33,35 @@ public void open() { @Override public void close() { this.requirePlaced(); - if (this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { + if (this.getBlockEntity().openersCounter.opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level level) { BlockState block = this.getBlockEntity().getBlockState(); int openCount = this.getBlockEntity().openersCounter.getOpenerCount(); - this.getBlockEntity().openersCounter.onAPIClose((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block); - this.getBlockEntity().openersCounter.openerAPICountChanged((net.minecraft.world.level.Level) this.getWorldHandle(), this.getPosition(), block, openCount, 0); + this.getBlockEntity().openersCounter.onCloseAPI(level, this.getPosition(), block); + this.getBlockEntity().openersCounter.openerCountChangedAPI(level, this.getPosition(), block, openCount, 0); } this.getBlockEntity().openersCounter.opened = false; } @Override - public CraftEnderChest copy() { - return new CraftEnderChest(this, null); + public boolean isOpen() { + return this.getBlockEntity().openersCounter.opened; } @Override - public CraftEnderChest copy(Location location) { - return new CraftEnderChest(this, location); + public boolean isBlocked() { + // Uses the same logic as EnderChestBlock's check for opening container + final BlockPos abovePos = this.getPosition().above(); + return this.isPlaced() && this.getWorldHandle().getBlockState(abovePos).isRedstoneConductor(this.getWorldHandle(), abovePos); } - // Paper start - More Lidded Block API @Override - public boolean isOpen() { - return getBlockEntity().openersCounter.opened; + public CraftEnderChest copy() { + return new CraftEnderChest(this, null); } - // Paper end - More Lidded Block API - // Paper start - More Chest Block API @Override - public boolean isBlocked() { - // Uses the same logic as EnderChestBlock's check for opening container - final net.minecraft.core.BlockPos abovePos = this.getPosition().above(); - return this.isPlaced() && this.getWorldHandle().getBlockState(abovePos).isRedstoneConductor(this.getWorldHandle(), abovePos); + public CraftEnderChest copy(Location location) { + return new CraftEnderChest(this, location); } - // Paper end - More Chest Block API } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java index a8b57a406b9f..33a7f3e3cc6a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java @@ -46,7 +46,7 @@ public short getBurnTime() { @Override public void setBurnTime(short burnTime) { this.getSnapshot().litTimeRemaining = burnTime; - this.data = this.data.trySetValue(AbstractFurnaceBlock.LIT, burnTime > 0); + this.block = this.block.trySetValue(AbstractFurnaceBlock.LIT, burnTime > 0); // only try, block data might have changed to something different that would not allow this property } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java index ba7227f95220..d5b7cae0925d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java @@ -43,7 +43,7 @@ public boolean update(boolean force, boolean applyPhysics) { boolean result = super.update(force, applyPhysics); if (result && this.isPlaced() && this.getType() == Material.JUKEBOX) { - this.getWorldHandle().setBlock(this.getPosition(), this.data, Block.UPDATE_ALL); + this.getWorldHandle().setBlock(this.getPosition(), this.block, Block.UPDATE_ALL); BlockEntity blockEntity = this.getBlockEntityFromWorld(); if (blockEntity instanceof JukeboxBlockEntity jukebox) { @@ -70,7 +70,7 @@ record = Material.AIR; @Override public boolean hasRecord() { - return this.data.getValueOrElse(JukeboxBlock.HAS_RECORD, false) && !this.getPlaying().isAir(); + return this.block.getValueOrElse(JukeboxBlock.HAS_RECORD, false) && !this.getPlaying().isAir(); } @Override @@ -86,7 +86,7 @@ public void setRecord(org.bukkit.inventory.ItemStack record) { JukeboxBlockEntity snapshot = this.getSnapshot(); snapshot.setSongItemWithoutPlaying(nms, snapshot.getSongPlayer().getTicksSinceSongStarted()); - this.data = this.data.trySetValue(JukeboxBlock.HAS_RECORD, !nms.isEmpty()); + this.block = this.block.trySetValue(JukeboxBlock.HAS_RECORD, !nms.isEmpty()); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java index b4b79f519ae8..2beb8ec07de1 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftMovingPiston.java @@ -27,7 +27,7 @@ public CraftMovingPiston copy(Location location) { // Paper start - Add Moving Piston API @Override public org.bukkit.block.data.BlockData getMovingBlock() { - return org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(this.getBlockEntity().getMovedState()); + return this.getBlockEntity().getMovedState().asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java index 0f08bc5f79ac..af76b93c9731 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java @@ -48,7 +48,7 @@ public void open() { if (!this.getBlockEntity().opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { net.minecraft.world.level.Level world = this.getBlockEntity().getLevel(); world.blockEvent(this.getPosition(), this.getBlockEntity().getBlockState().getBlock(), 1, 1); - world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_OPEN, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); + world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_OPEN, SoundSource.BLOCKS, 0.5F, world.getRandom().nextFloat() * 0.1F + 0.9F); } this.getBlockEntity().opened = true; } @@ -59,7 +59,7 @@ public void close() { if (this.getBlockEntity().opened && this.getWorldHandle() instanceof net.minecraft.world.level.Level) { net.minecraft.world.level.Level world = this.getBlockEntity().getLevel(); world.blockEvent(this.getPosition(), this.getBlockEntity().getBlockState().getBlock(), 1, 0); - world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_CLOSE, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); // Paper - More Lidded Block API (Wrong sound) + world.playSound(null, this.getPosition(), SoundEvents.SHULKER_BOX_CLOSE, SoundSource.BLOCKS, 0.5F, world.getRandom().nextFloat() * 0.1F + 0.9F); // Paper - More Lidded Block API (Wrong sound) } this.getBlockEntity().opened = false; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftTrialSpawner.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftTrialSpawner.java index 6230ef5030f0..4fedf2554b25 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftTrialSpawner.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftTrialSpawner.java @@ -143,23 +143,23 @@ public void stopTrackingEntity(Entity entity) { @Override public boolean isOminous() { - return this.data.getValueOrElse(TrialSpawnerBlock.OMINOUS, false); + return this.block.getValueOrElse(TrialSpawnerBlock.OMINOUS, false); } @Override public void setOminous(boolean ominous) { - if (!this.data.hasProperty(TrialSpawnerBlock.OMINOUS)) { + if (!this.block.hasProperty(TrialSpawnerBlock.OMINOUS)) { return; // block data changed } this.getSnapshot().trialSpawner.isOminous = ominous; if (ominous) { - this.data = this.data.setValue(TrialSpawnerBlock.OMINOUS, true); + this.block = this.block.setValue(TrialSpawnerBlock.OMINOUS, true); // TODO: Consider calling TrialSpawnerData#resetAfterBecomingOminous in update(...), but note that method also removes entities return; } - this.data = this.data.setValue(TrialSpawnerBlock.OMINOUS, false); + this.block = this.block.setValue(TrialSpawnerBlock.OMINOUS, false); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java index 68bb1b852273..7cef83107fab 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java @@ -5,30 +5,39 @@ import com.google.common.collect.ImmutableSet; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import java.util.stream.Stream; import net.minecraft.commands.arguments.blocks.BlockStateParser; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateHolder; -import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.apache.commons.lang3.mutable.MutableDouble; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SoundGroup; import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; import org.bukkit.block.BlockSupport; import org.bukkit.block.BlockType; import org.bukkit.block.PistonMoveReaction; @@ -41,187 +50,143 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import org.bukkit.craftbukkit.block.CraftBlockSupport; -import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftItemType; import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.craftbukkit.util.CraftVoxelShape; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.Nullable; public class CraftBlockData implements BlockData { - private net.minecraft.world.level.block.state.BlockState state; - private Map, Comparable> parsedStates; + private BlockState state; + private List> parsedStates; - protected CraftBlockData() { - throw new AssertionError("Template Constructor"); - } - - protected CraftBlockData(net.minecraft.world.level.block.state.BlockState state) { + protected CraftBlockData(BlockState state) { this.state = state; } @Override public Material getMaterial() { - return this.state.getBukkitMaterial(); // Paper - optimise getType calls + return this.state.getBukkitMaterial(); } - public net.minecraft.world.level.block.state.BlockState getState() { + public BlockState getState() { return this.state; } - /** - * Get a given BlockStateEnum's value as its Bukkit counterpart. - * - * @param nms the NMS state to convert - * @param bukkit the Bukkit class - * @param the type - * @return the matching Bukkit type - */ - protected > B get(EnumProperty nms, Class bukkit) { - return CraftBlockData.toBukkit(this.state.getValue(nms), bukkit); - } - - /** - * Convert all values from the given BlockStateEnum to their appropriate - * Bukkit counterpart. - * - * @param nms the NMS state to get values from - * @param bukkit the bukkit class to convert the values to - * @param the bukkit class type - * @return an immutable Set of values in their appropriate Bukkit type - */ - @SuppressWarnings("unchecked") - protected > Set getValues(EnumProperty nms, Class bukkit) { - ImmutableSet.Builder values = ImmutableSet.builder(); - - for (Enum e : nms.getPossibleValues()) { - values.add(CraftBlockData.toBukkit(e, bukkit)); - } - - return values.build(); - } - - /** - * Set a given {@link EnumProperty} with the matching enum from Bukkit. - * - * @param nms the NMS BlockStateEnum to set - * @param bukkit the matching Bukkit Enum - * @param the Bukkit type - * @param the NMS type - */ - protected , N extends Enum & StringRepresentable> void set(EnumProperty nms, Enum bukkit) { - this.parsedStates = null; - this.state = this.state.setValue(nms, CraftBlockData.toNMS(bukkit, nms.getValueClass())); - } - @Override public BlockData merge(BlockData data) { CraftBlockData craft = (CraftBlockData) data; - Preconditions.checkArgument(craft.parsedStates != null, "Data not created via string parsing"); - Preconditions.checkArgument(this.state.getBlock() == craft.state.getBlock(), "States have different types (got %s, expected %s)", data, this); + Preconditions.checkArgument(craft.parsedStates != null, "Block data not created via string parsing"); + Preconditions.checkArgument(this.state.getBlock() == craft.state.getBlock(), "States have different types (got %s, expected %s)", craft.state.getBlock(), this.state.getBlock()); CraftBlockData clone = (CraftBlockData) this.clone(); clone.parsedStates = null; - for (Property parsed : craft.parsedStates.keySet()) { - clone.state = clone.state.setValue(parsed, craft.state.getValue(parsed)); + for (Property.Value parsed : craft.parsedStates) { + clone.state = setValue(clone.state, parsed); } return clone; } + private static > BlockState setValue(final BlockState state, final Property.Value propertyValue) { + return state.setValue(propertyValue.property(), propertyValue.value()); + } + + private > BlockState copyProperty(BlockState source, BlockState target, Property property) { + return target.setValue(property, source.getValue(property)); + } + @Override public boolean matches(BlockData data) { - if (data == null) { - return false; - } - if (!(data instanceof CraftBlockData)) { + if (!(data instanceof final CraftBlockData craft)) { return false; } - - CraftBlockData craft = (CraftBlockData) data; if (this.state.getBlock() != craft.state.getBlock()) { return false; } // Fastpath an exact match - boolean exactMatch = this.equals(data); + if (this.equals(data)) { + return true; + } // If that failed, do a merge and check - if (!exactMatch && craft.parsedStates != null) { + if (craft.parsedStates != null) { return this.merge(data).equals(this); } - - return exactMatch; + return false; } - private static final Map>, Enum[]> ENUM_VALUES = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - cache block data strings; make thread safe + private static final ClassValue[]> ENUM_VALUES = new ClassValue<>() { + @Override + protected Enum[] computeValue(final Class klass) { + return (Enum[]) klass.getEnumConstants(); + } + }; - /** - * Convert an NMS Enum (usually a BlockStateEnum) to its appropriate Bukkit - * enum from the given class. - * - * @throws IllegalStateException if the Enum could not be converted - */ - @SuppressWarnings("unchecked") - public static > B toBukkit(Enum nms, Class bukkit) { - if (nms instanceof Direction) { - return (B) CraftBlock.notchToBlockFace((Direction) nms); + public static > B fromVanilla(Enum internal, Class bukkit) { + final Object rawValue; + if (internal instanceof Direction direction) { + rawValue = CraftBlock.notchToBlockFace(direction); + } else { + rawValue = ENUM_VALUES.get(bukkit)[internal.ordinal()]; } - return (B) CraftBlockData.ENUM_VALUES.computeIfAbsent(bukkit, Class::getEnumConstants)[nms.ordinal()]; - } - - /** - * Convert a given Bukkit enum to its matching NMS enum type. - * - * @param bukkit the Bukkit enum to convert - * @param nms the NMS class - * @return the matching NMS type - * @throws IllegalStateException if the Enum could not be converted - */ - @SuppressWarnings("unchecked") - public static & StringRepresentable> N toNMS(Enum bukkit, Class nms) { - if (bukkit instanceof BlockFace) { - return (N) CraftBlock.blockFaceToNotch((BlockFace) bukkit); + return bukkit.cast(rawValue); + } + + public static & StringRepresentable> M toVanilla(Enum bukkit, Class internalClass) { + final Object rawValue; + if (bukkit instanceof BlockFace face) { + rawValue = CraftBlock.blockFaceToNotch(face); + } else { + rawValue = ENUM_VALUES.get(internalClass)[bukkit.ordinal()]; + } + return internalClass.cast(rawValue); + } + + protected > A get(EnumProperty property, Class bukkitClass) { + return fromVanilla(this.state.getValue(property), bukkitClass); + } + + protected & StringRepresentable, A extends Enum> @Unmodifiable Set getValues(EnumProperty property, Class bukkitClass) { + List values = property.getPossibleValues(); + ImmutableSet.Builder result = ImmutableSet.builderWithExpectedSize(values.size()); + + for (M e : values) { + result.add(fromVanilla(e, bukkitClass)); } - return (N) CraftBlockData.ENUM_VALUES.computeIfAbsent(nms, Class::getEnumConstants)[bukkit.ordinal()]; - } - - /** - * Get the current value of a given state. - * - * @param ibs the state to check - * @param the type - * @return the current value of the given state - */ - protected > T get(Property ibs) { - // Straight integer or boolean getter - return this.state.getValue(ibs); - } - - /** - * Set the specified state's value. - * - * @param ibs the state to set - * @param v the new value - * @param the state's type - * @param the value's type. Must match the state's type. - */ - public , V extends T> void set(Property ibs, V v) { - // Straight integer or boolean setter + + return result.build(); + } + + protected , M extends Enum & StringRepresentable> void set(EnumProperty property, A bukkit) { this.parsedStates = null; - this.state = this.state.setValue(ibs, v); + this.state = this.state.setValue(property, toVanilla(bukkit, property.getValueClass())); + } + + // Straight integer or boolean getter + protected > T get(Property property) { + return this.state.getValue(property); + } + + // Straight integer or boolean setter + public , V extends T> void set(Property property, V value) { + this.parsedStates = null; + this.state = this.state.setValue(property, value); } @Override public String getAsString() { - return this.toString(this.state.getValues()); + return this.toString(this.state.getValues(), this.state.isSingletonState()); } @Override public String getAsString(boolean hideUnspecified) { - return (hideUnspecified && this.parsedStates != null) ? this.toString(this.parsedStates) : this.getAsString(); + return (hideUnspecified && this.parsedStates != null) ? this.toString(this.parsedStates.stream(), this.parsedStates.isEmpty()) : this.getAsString(); } @Override @@ -238,33 +203,25 @@ public String toString() { return "CraftBlockData{" + this.getAsString() + "}"; } - // Mimicked from BlockDataAbstract#toString() - public String toString(Map, Comparable> states) { + // Mimicked from StateHolder#toString() prefixed by just the key instead of Block{key} + public String toString(Stream> states, boolean singleton) { StringBuilder stateString = new StringBuilder(BuiltInRegistries.BLOCK.getKey(this.state.getBlock()).toString()); - - if (!states.isEmpty()) { + if (!singleton) { stateString.append('['); - stateString.append(states.entrySet().stream().map(StateHolder.PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(","))); + stateString.append(states.map(Property.Value::toString).collect(Collectors.joining(","))); stateString.append(']'); } - return stateString.toString(); } public Map toStates(boolean hideUnspecified) { - return (hideUnspecified && this.parsedStates != null) ? CraftBlockData.toStates(this.parsedStates) : CraftBlockData.toStates(this.state.getValues()); - } - - private static Map toStates(Map, Comparable> states) { - Map compound = new HashMap<>(); - - for (Map.Entry, Comparable> entry : states.entrySet()) { - Property iblockstate = (Property) entry.getKey(); - - compound.put(iblockstate.getName(), iblockstate.getName(entry.getValue())); + Map serializedStates = new HashMap<>(); + if (hideUnspecified && this.parsedStates != null) { + this.parsedStates.forEach(state -> serializedStates.put(state.property().getName(), state.valueName())); + } else { + this.state.getValues().forEach(state -> serializedStates.put(state.property().getName(), state.valueName())); } - - return compound; + return serializedStates; } @Override @@ -277,69 +234,6 @@ public int hashCode() { return this.state.hashCode(); } - protected static BooleanProperty getBoolean(String name) { - throw new AssertionError("Template Method"); - } - - protected static BooleanProperty getBoolean(String name, boolean optional) { - throw new AssertionError("Template Method"); - } - - protected static EnumProperty getEnum(String name) { - throw new AssertionError("Template Method"); - } - - protected static IntegerProperty getInteger(String name) { - throw new AssertionError("Template Method"); - } - - protected static BooleanProperty getBoolean(Class block, String name) { - return (BooleanProperty) CraftBlockData.getState(block, name, false); - } - - protected static BooleanProperty getBoolean(Class block, String name, boolean optional) { - return (BooleanProperty) CraftBlockData.getState(block, name, optional); - } - - protected static EnumProperty getEnum(Class block, String name) { - return (EnumProperty) CraftBlockData.getState(block, name, false); - } - - protected static IntegerProperty getInteger(Class block, String name) { - return (IntegerProperty) CraftBlockData.getState(block, name, false); - } - - /** - * Get a specified {@link Property} from a given block's class with a - * given name - * - * @param block the class to retrieve the state from - * @param name the name of the state to retrieve - * @param optional if the state can be null - * @return the specified state or null - * @throws IllegalStateException if the state is null and {@code optional} - * is false. - */ - private static Property getState(Class block, String name, boolean optional) { - Property state = null; - - for (Block instance : BuiltInRegistries.BLOCK) { - if (instance.getClass() == block) { - if (state == null) { - state = instance.getStateDefinition().getProperty(name); - } else { - Property newState = instance.getStateDefinition().getProperty(name); - - Preconditions.checkState(state == newState, "State mismatch %s,%s", state, newState); - } - } - } - - Preconditions.checkState(optional || state != null, "Null state for %s,%s", block, name); - - return state; - } - public static final BlockFace[] ROTATION_CYCLE = { BlockFace.SOUTH, BlockFace.SOUTH_SOUTH_WEST, BlockFace.SOUTH_WEST, BlockFace.WEST_SOUTH_WEST, BlockFace.WEST, BlockFace.WEST_NORTH_WEST, BlockFace.NORTH_WEST, BlockFace.NORTH_NORTH_WEST, @@ -347,21 +241,11 @@ private static Property getState(Class block, String name, b BlockFace.EAST, BlockFace.EAST_SOUTH_EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH_SOUTH_EAST }; - /** - * Get the maximum value allowed by the BlockStateInteger. - * - * @param state the state to check - * @return the maximum value allowed - */ - protected static int getMax(IntegerProperty state) { - return state.max; - } - - private static final Map, Function> MAP = new HashMap<>(); + private static final Map, Function> INSTANCE_CREATOR = new HashMap<>(); static { // - // Start generate - CraftBlockData#MAP + // Start generate - CraftBlockData#INSTANCE_CREATOR register(net.minecraft.world.level.block.AmethystClusterBlock.class, org.bukkit.craftbukkit.block.impl.CraftAmethystCluster::new); register(net.minecraft.world.level.block.AnvilBlock.class, org.bukkit.craftbukkit.block.impl.CraftAnvil::new); register(net.minecraft.world.level.block.AttachedStemBlock.class, org.bukkit.craftbukkit.block.impl.CraftAttachedStem::new); @@ -424,7 +308,7 @@ protected static int getMax(IntegerProperty state) { register(net.minecraft.world.level.block.EndPortalFrameBlock.class, org.bukkit.craftbukkit.block.impl.CraftEndPortalFrame::new); register(net.minecraft.world.level.block.EndRodBlock.class, org.bukkit.craftbukkit.block.impl.CraftEndRod::new); register(net.minecraft.world.level.block.EnderChestBlock.class, org.bukkit.craftbukkit.block.impl.CraftEnderChest::new); - register(net.minecraft.world.level.block.FarmBlock.class, org.bukkit.craftbukkit.block.impl.CraftFarm::new); + register(net.minecraft.world.level.block.FarmlandBlock.class, org.bukkit.craftbukkit.block.impl.CraftFarmland::new); register(net.minecraft.world.level.block.FenceBlock.class, org.bukkit.craftbukkit.block.impl.CraftFence::new); register(net.minecraft.world.level.block.FenceGateBlock.class, org.bukkit.craftbukkit.block.impl.CraftFenceGate::new); register(net.minecraft.world.level.block.FireBlock.class, org.bukkit.craftbukkit.block.impl.CraftFire::new); @@ -498,7 +382,7 @@ protected static int getMax(IntegerProperty state) { register(net.minecraft.world.level.block.SmokerBlock.class, org.bukkit.craftbukkit.block.impl.CraftSmoker::new); register(net.minecraft.world.level.block.SnifferEggBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnifferEgg::new); register(net.minecraft.world.level.block.SnowLayerBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnowLayer::new); - register(net.minecraft.world.level.block.SnowyDirtBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnowyDirt::new); + register(net.minecraft.world.level.block.SnowyBlock.class, org.bukkit.craftbukkit.block.impl.CraftSnowy::new); register(net.minecraft.world.level.block.StainedGlassPaneBlock.class, org.bukkit.craftbukkit.block.impl.CraftStainedGlassPane::new); register(net.minecraft.world.level.block.StairBlock.class, org.bukkit.craftbukkit.block.impl.CraftStair::new); register(net.minecraft.world.level.block.StandingSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftStandingSign::new); @@ -550,88 +434,73 @@ protected static int getMax(IntegerProperty state) { register(net.minecraft.world.level.block.piston.MovingPistonBlock.class, org.bukkit.craftbukkit.block.impl.CraftMovingPiston::new); register(net.minecraft.world.level.block.piston.PistonBaseBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonBase::new); register(net.minecraft.world.level.block.piston.PistonHeadBlock.class, org.bukkit.craftbukkit.block.impl.CraftPistonHead::new); - // End generate - CraftBlockData#MAP + // End generate - CraftBlockData#INSTANCE_CREATOR // } - private static void register(Class nms, Function bukkit) { - Preconditions.checkState(CraftBlockData.MAP.put(nms, bukkit) == null, "Duplicate mapping %s->%s", nms, bukkit); + private static void register(Class blockClass, Function newInstance) { + Preconditions.checkState(INSTANCE_CREATOR.put(blockClass, newInstance) == null, "Duplicate mapping %s->%s", blockClass, newInstance); } - // Paper start - cache block data strings - private static Map stringDataCache = new java.util.concurrent.ConcurrentHashMap<>(); + private static final Map ENCODER_CACHE = new ConcurrentHashMap<>(); static { - // cache all of the default states at startup, will not cache ones with the custom states inside of the + // cache all the default states at startup, will not cache ones with the custom states inside of the // brackets in a different order, though reloadCache(); } public static void reloadCache() { - stringDataCache.clear(); - Block.BLOCK_STATE_REGISTRY.forEach(blockData -> stringDataCache.put(blockData.toString(), blockData.createCraftBlockData())); + ENCODER_CACHE.clear(); + Block.BLOCK_STATE_REGISTRY.forEach(state -> { + CraftBlockData data = state.asBlockData(); + ENCODER_CACHE.put(data.getAsString(), data); + }); } - // Paper end - cache block data strings - - public static CraftBlockData newData(BlockType blockType, String data) { - // Paper start - cache block data strings + public static CraftBlockData fromString(@Nullable BlockType blockType, @Nullable String data) { + StringBuilder serializedData = new StringBuilder(); if (blockType != null) { - Block block = CraftBlockType.bukkitToMinecraftNew(blockType); - if (block != null) { - net.minecraft.resources.Identifier key = BuiltInRegistries.BLOCK.getKey(block); - data = data == null ? key.toString() : key + data; - } + serializedData.append(blockType.key().asString()); } - CraftBlockData cached = stringDataCache.computeIfAbsent(data, s -> createNewData(null, s)); - return (CraftBlockData) cached.clone(); - } - - private static CraftBlockData createNewData(BlockType blockType, String data) { - // Paper end - cache block data strings - net.minecraft.world.level.block.state.BlockState blockData; - Block block = blockType == null ? null : ((CraftBlockType) blockType).getHandle(); - Map, Comparable> parsed = null; - - // Data provided, use it if (data != null) { - try { - // Material provided, force that material in - if (block != null) { - data = BuiltInRegistries.BLOCK.getKey(block) + data; - } + serializedData.append(data); + } - StringReader reader = new StringReader(data); - BlockStateParser.BlockResult arg = BlockStateParser.parseForBlock(CraftRegistry.getMinecraftRegistry(Registries.BLOCK), reader, false); - Preconditions.checkArgument(!reader.canRead(), "Spurious trailing data: " + data); + CraftBlockData cached = ENCODER_CACHE.computeIfAbsent(serializedData.toString(), CraftBlockData::parseData); + return (CraftBlockData) cached.clone(); + } - blockData = arg.blockState(); - parsed = arg.properties(); - } catch (CommandSyntaxException ex) { - throw new IllegalArgumentException("Could not parse data: " + data, ex); + private static CraftBlockData parseData(String serializedData) { + final BlockStateParser.BlockResult result; + try { + StringReader reader = new StringReader(serializedData); + result = BlockStateParser.parseForBlock(CraftRegistry.getMinecraftRegistry(Registries.BLOCK), reader, false); + if (reader.canRead()) { + throw new IllegalArgumentException("Spurious trailing data: " + reader.getRemaining()); } - } else { - blockData = block.defaultBlockState(); + } catch (CommandSyntaxException ex) { + throw new IllegalArgumentException("Could not parse data: " + serializedData, ex); } - CraftBlockData craft = CraftBlockData.fromData(blockData); - craft.parsedStates = parsed; - return craft; + CraftBlockData data = result.blockState().asBlockData(); + List> parsed = new ArrayList<>(result.properties().size()); + result.properties().forEach((property, value) -> { + parsed.add(StateHolder.createValue(property, value)); + }); + + data.parsedStates = parsed; + return data; } - // Paper start - optimize creating BlockData to not need a map lookup static { // Initialize cached data for all BlockState instances after registration - Block.BLOCK_STATE_REGISTRY.iterator().forEachRemaining(net.minecraft.world.level.block.state.BlockState::createCraftBlockData); - } - public static CraftBlockData fromData(net.minecraft.world.level.block.state.BlockState data) { - return data.createCraftBlockData(); + Block.BLOCK_STATE_REGISTRY.forEach(BlockState::asBlockData); } - public static CraftBlockData createData(net.minecraft.world.level.block.state.BlockState data) { - // Paper end - return CraftBlockData.MAP.getOrDefault(data.getBlock().getClass(), CraftBlockData::new).apply(data); + public static CraftBlockData createData(BlockState state) { + return INSTANCE_CREATOR.getOrDefault(state.getBlock().getClass(), CraftBlockData::new).apply(state); } @Override @@ -657,13 +526,11 @@ public boolean requiresCorrectToolForDrops() { @Override public boolean isPreferredTool(ItemStack tool) { Preconditions.checkArgument(tool != null, "tool must not be null"); - - net.minecraft.world.item.ItemStack nms = CraftItemStack.asNMSCopy(tool); - return CraftBlockData.isPreferredTool(this.state, nms); + return isPreferredTool(this.state, CraftItemStack.asNMSCopy(tool)); } - public static boolean isPreferredTool(net.minecraft.world.level.block.state.BlockState iblockdata, net.minecraft.world.item.ItemStack nmsItem) { - return !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata); + public static boolean isPreferredTool(BlockState state, net.minecraft.world.item.ItemStack item) { + return !state.requiresCorrectToolForDrops() || item.isCorrectToolForDrops(state); } @Override @@ -695,10 +562,9 @@ public boolean isFaceSturdy(BlockFace face, BlockSupport support) { Preconditions.checkArgument(face != null, "face must not be null"); Preconditions.checkArgument(support != null, "support must not be null"); - return this.state.isFaceSturdy(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CraftBlock.blockFaceToNotch(face), CraftBlockSupport.toNMS(support)); + return this.state.isFaceSturdy(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CraftBlock.blockFaceToNotch(face), CraftBlockSupport.toMinecraft(support)); } - // Paper start @Override public org.bukkit.util.VoxelShape getCollisionShape(Location location) { Preconditions.checkArgument(location != null, "location must not be null"); @@ -707,10 +573,9 @@ public org.bukkit.util.VoxelShape getCollisionShape(Location location) { Preconditions.checkArgument(world != null, "location must not have a null world"); BlockPos position = CraftLocation.toBlockPosition(location); - net.minecraft.world.phys.shapes.VoxelShape shape = this.state.getCollisionShape(world.getHandle(), position); - return new org.bukkit.craftbukkit.util.CraftVoxelShape(shape); + VoxelShape shape = this.state.getCollisionShape(world.getHandle(), position); + return new CraftVoxelShape(shape); } - // Paper end @Override public Color getMapColor() { @@ -735,45 +600,39 @@ public void mirror(Mirror mirror) { @Override public void copyTo(BlockData blockData) { CraftBlockData other = (CraftBlockData) blockData; - net.minecraft.world.level.block.state.BlockState nms = other.state; + BlockState otherState = other.state; for (Property property : this.state.getBlock().getStateDefinition().getProperties()) { - if (nms.hasProperty(property)) { - nms = this.copyProperty(this.state, nms, property); + if (otherState.hasProperty(property)) { + otherState = this.copyProperty(this.state, otherState, property); } } - other.state = nms; - } - - private > net.minecraft.world.level.block.state.BlockState copyProperty(net.minecraft.world.level.block.state.BlockState source, net.minecraft.world.level.block.state.BlockState target, Property property) { - return target.setValue(property, source.getValue(property)); + other.state = otherState; } - @NotNull @Override - public BlockState createBlockState() { + public org.bukkit.block.BlockState createBlockState() { return CraftBlockStates.getBlockState(this.state, null); } - // Paper start - destroy speed API @Override - public float getDestroySpeed(final ItemStack itemStack, final boolean considerEnchants) { - net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(itemStack); - float speed = nmsItemStack.getDestroySpeed(this.state); + public float getDestroySpeed(final ItemStack item, final boolean considerEnchants) { + net.minecraft.world.item.ItemStack itemStack = CraftItemStack.unwrap(item); + float speed = itemStack.getDestroySpeed(this.state); if (speed > 1.0F && considerEnchants) { - final net.minecraft.core.Holder attribute = net.minecraft.world.entity.ai.attributes.Attributes.MINING_EFFICIENCY; + final Holder attribute = Attributes.MINING_EFFICIENCY; // Logic sourced from AttributeInstance#calculateValue final double initialBaseValue = attribute.value().getDefaultValue(); - final org.apache.commons.lang3.mutable.MutableDouble modifiedBaseValue = new org.apache.commons.lang3.mutable.MutableDouble(initialBaseValue); - final org.apache.commons.lang3.mutable.MutableDouble baseValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); - final org.apache.commons.lang3.mutable.MutableDouble totalValMul = new org.apache.commons.lang3.mutable.MutableDouble(1); + final MutableDouble modifiedBaseValue = new MutableDouble(initialBaseValue); + final MutableDouble baseValMul = new MutableDouble(1); + final MutableDouble totalValMul = new MutableDouble(1); - net.minecraft.world.item.enchantment.EnchantmentHelper.forEachModifier( - nmsItemStack, net.minecraft.world.entity.EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { + EnchantmentHelper.forEachModifier( + itemStack, EquipmentSlot.MAINHAND, (_, attributeModifier) -> { switch (attributeModifier.operation()) { case ADD_VALUE -> modifiedBaseValue.add(attributeModifier.amount()); case ADD_MULTIPLIED_BASE -> baseValMul.add(attributeModifier.amount()); - case ADD_MULTIPLIED_TOTAL -> totalValMul.setValue(totalValMul.doubleValue() * (1D + attributeModifier.amount())); + case ADD_MULTIPLIED_TOTAL -> totalValMul.setValue(totalValMul.doubleValue() * (1.0 + attributeModifier.amount())); } } ); @@ -784,14 +643,11 @@ public float getDestroySpeed(final ItemStack itemStack, final boolean considerEn } return speed; } - // Paper end - destroy speed API - // Paper start - Block tick API @Override public boolean isRandomlyTicked() { return this.state.isRandomlyTicking(); } - // Paper end - Block tick API @Override public boolean isReplaceable() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftBossBar.java b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftBossBar.java index 8430d131bbc1..80d8a8ae5316 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftBossBar.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftBossBar.java @@ -26,6 +26,7 @@ public class CraftBossBar implements BossBar { public CraftBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) { this.handle = new ServerBossEvent( + net.minecraft.util.Mth.createInsecureUUID(net.minecraft.util.RandomSource.create()), CraftChatMessage.fromString(title, true)[0], this.convertColor(color), this.convertStyle(style) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java index 9d96237cecbc..3c87a0156ffa 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftDragonBattle.java @@ -8,8 +8,8 @@ import java.util.stream.Collectors; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.dimension.end.DragonRespawnAnimation; -import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.dimension.end.DragonRespawnStage; +import net.minecraft.world.level.dimension.end.EnderDragonFight; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.boss.BossBar; @@ -22,9 +22,9 @@ public class CraftDragonBattle implements DragonBattle { - private final EndDragonFight handle; + private final EnderDragonFight handle; - public CraftDragonBattle(EndDragonFight handle) { + public CraftDragonBattle(EnderDragonFight handle) { this.handle = handle; } @@ -41,16 +41,16 @@ public BossBar getBossBar() { @Override public Location getEndPortalLocation() { - if (this.handle.portalLocation == null) { + if (this.handle.exitPortalLocation == null) { return null; } - return CraftLocation.toBukkit(this.handle.portalLocation, this.handle.level); + return CraftLocation.toBukkit(this.handle.exitPortalLocation, this.handle.level); } @Override public boolean generateEndPortal(boolean withPortals) { - if (this.handle.portalLocation != null || this.handle.findExitPortal() != null) { + if (this.handle.exitPortalLocation != null || this.handle.findExitPortal() != null) { return false; } @@ -65,7 +65,7 @@ public boolean hasBeenPreviouslyKilled() { @Override public void setPreviouslyKilled(boolean previouslyKilled) { - this.handle.previouslyKilled = previouslyKilled; + this.handle.hasPreviouslyKilledDragon = previouslyKilled; } @Override @@ -77,7 +77,7 @@ public void initiateRespawn() { public boolean initiateRespawn(Collection list) { if (this.hasBeenPreviouslyKilled() && this.getRespawnPhase() == RespawnPhase.NONE) { // Copy from EndDragonFight#tryRespawn for generate exit portal if not exists - if (this.handle.portalLocation == null) { + if (this.handle.exitPortalLocation == null) { BlockPattern.BlockPatternMatch patternMatch = this.handle.findExitPortal(); if (patternMatch == null) { this.handle.spawnExitPortal(true); @@ -131,17 +131,17 @@ public boolean equals(Object obj) { return obj instanceof CraftDragonBattle && ((CraftDragonBattle) obj).handle == this.handle; } - private RespawnPhase toBukkitRespawnPhase(DragonRespawnAnimation phase) { + private RespawnPhase toBukkitRespawnPhase(DragonRespawnStage phase) { return (phase != null) ? RespawnPhase.values()[phase.ordinal()] : RespawnPhase.NONE; } - private DragonRespawnAnimation toNMSRespawnPhase(RespawnPhase phase) { - return (phase != RespawnPhase.NONE) ? DragonRespawnAnimation.values()[phase.ordinal()] : null; + private DragonRespawnStage toNMSRespawnPhase(RespawnPhase phase) { + return (phase != RespawnPhase.NONE) ? DragonRespawnStage.values()[phase.ordinal()] : null; } @Override public int getGatewayCount() { - return EndDragonFight.GATEWAY_COUNT - this.handle.gateways.size(); + return EnderDragonFight.GATEWAY_COUNT - this.handle.gateways.size(); } @Override @@ -161,8 +161,9 @@ public List getRespawnCrystals() { } final List enderCrystals = new ArrayList<>(); - for (final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal : this.handle.respawnCrystals) { - if (!endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { + for (final net.minecraft.world.entity.EntityReference ref : this.handle.respawnCrystals) { + final net.minecraft.world.entity.boss.enderdragon.EndCrystal endCrystal = ref.getEntity(this.handle.level, net.minecraft.world.entity.boss.enderdragon.EndCrystal.class); + if (endCrystal != null && !endCrystal.isRemoved() && endCrystal.isAlive() && endCrystal.valid) { enderCrystals.add(((EnderCrystal) endCrystal.getBukkitEntity())); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftKeyedBossbar.java b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftKeyedBossbar.java index e380793e3436..8ea17c380fd6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftKeyedBossbar.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/boss/CraftKeyedBossbar.java @@ -13,7 +13,7 @@ public CraftKeyedBossbar(CustomBossEvent bossBattleCustom) { @Override public NamespacedKey getKey() { - return CraftNamespacedKey.fromMinecraft(this.getHandle().getTextId()); + return CraftNamespacedKey.fromMinecraft(this.getHandle().customId()); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/configuration/ConfigSerializationUtil.java b/paper-server/src/main/java/org/bukkit/craftbukkit/configuration/ConfigSerializationUtil.java index 38b07b508205..ffbcf189b870 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/configuration/ConfigSerializationUtil.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/configuration/ConfigSerializationUtil.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.configuration; +import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -50,6 +51,12 @@ public static void setHolderSet(Map result, String key, HolderSe .ifRight(list -> result.put(key, list.stream().map((entry) -> entry.unwrapKey().orElseThrow().identifier().toString()).toList())); // List } + public static void setHolderSet(ImmutableMap.Builder result, String key, HolderSet holders) { + holders.unwrap() + .ifLeft(tag -> result.put(key, "#" + tag.location().toString())) // Tag + .ifRight(list -> result.put(key, list.stream().map((entry) -> entry.unwrapKey().orElseThrow().identifier().toString()).toList())); // List + } + public static HolderSet getHolderSet(Object from, ResourceKey> registryKey) { Registry registry = CraftRegistry.getMinecraftRegistry(registryKey); if (from instanceof String parseString && parseString.startsWith("#")) { // Tag diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAgeable.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAgeable.java index 809639b79db4..b39c2d50e06a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAgeable.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAgeable.java @@ -26,12 +26,12 @@ public void setAge(int age) { @Override public void setAgeLock(boolean lock) { - this.getHandle().ageLocked = lock; + this.getHandle().setAgeLocked(lock); } @Override public boolean getAgeLock() { - return this.getHandle().ageLocked; + return this.getHandle().isAgeLocked(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBlockDisplay.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBlockDisplay.java index 6502c0622e6e..173a6cce4593 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBlockDisplay.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBlockDisplay.java @@ -19,7 +19,7 @@ public net.minecraft.world.entity.Display.BlockDisplay getHandle() { @Override public BlockData getBlock() { - return CraftBlockData.fromData(this.getHandle().getBlockState()); + return this.getHandle().getBlockState().asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java index 02a4a8641050..e4a0df348522 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBoat.java @@ -44,7 +44,7 @@ public double getMaxSpeed() { @Override public void setMaxSpeed(double speed) { - if (speed >= 0D) { + if (speed >= 0) { this.getHandle().maxSpeed = speed; } } @@ -56,7 +56,7 @@ public double getOccupiedDeceleration() { @Override public void setOccupiedDeceleration(double speed) { - if (speed >= 0D) { + if (speed >= 0) { this.getHandle().occupiedDeceleration = speed; } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java index f71864abb9ef..3daecbbcc55d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java @@ -1,9 +1,7 @@ package org.bukkit.craftbukkit.entity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Breeze; -import org.bukkit.entity.LivingEntity; public class CraftBreeze extends CraftMonster implements Breeze { @@ -16,10 +14,12 @@ public net.minecraft.world.entity.monster.breeze.Breeze getHandle() { return (net.minecraft.world.entity.monster.breeze.Breeze) this.entity; } + /* // TODO - snapshot - reimplement? but without reintroducing MC-199589 @Override public void setTarget(LivingEntity target) { super.setTarget(target); - net.minecraft.world.entity.LivingEntity entityLivingTarget = (target instanceof CraftLivingEntity craftLivingEntity) ? craftLivingEntity.getHandle() : null; - this.getHandle().getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, entityLivingTarget); // SPIGOT-7957: We need override memory for set target and trigger attack behaviours + net.minecraft.world.entity.LivingEntity attackTarget = (target instanceof CraftLivingEntity craftLivingEntity) ? craftLivingEntity.getHandle() : null; + this.getHandle().getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, attackTarget); // SPIGOT-7957: We need override memory for set target and trigger attack behaviours } + */ } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java index 0ff5f7417259..8eb1d46ec221 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java @@ -1,9 +1,11 @@ package org.bukkit.craftbukkit.entity; import com.google.common.base.Preconditions; +import io.papermc.paper.registry.HolderableBase; import io.papermc.paper.util.OldEnumHolderable; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.animal.feline.CatSoundVariant; import net.minecraft.world.entity.animal.feline.CatVariant; import org.bukkit.DyeColor; import org.bukkit.craftbukkit.CraftRegistry; @@ -33,6 +35,18 @@ public void setCatType(Type type) { this.getHandle().setVariant(CraftType.bukkitToMinecraftHolder(type)); } + @Override + public SoundVariant getSoundVariant() { + return CraftSoundVariant.minecraftHolderToBukkit(this.getHandle().getSoundVariant()); + } + + @Override + public void setSoundVariant(final SoundVariant variant) { + Preconditions.checkArgument(variant != null, "variant cannot be null"); + + this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(variant)); + } + @Override public DyeColor getCollarColor() { return DyeColor.getByWoolData((byte) this.getHandle().getCollarColor().getId()); @@ -59,6 +73,21 @@ public CraftType(final Holder holder) { } } + public static class CraftSoundVariant extends HolderableBase implements SoundVariant { + + public static SoundVariant minecraftHolderToBukkit(Holder minecraft) { + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.CAT_SOUND_VARIANT); + } + + public static Holder bukkitToMinecraftHolder(SoundVariant bukkit) { + return CraftRegistry.bukkitToMinecraftHolder(bukkit); + } + + public CraftSoundVariant(final Holder holder) { + super(holder); + } + } + @Override public void setLyingDown(boolean lyingDown) { this.getHandle().setLying(lyingDown); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java index 1e015dc87c62..855ddda60c1a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftChicken.java @@ -4,6 +4,7 @@ import io.papermc.paper.registry.HolderableBase; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.animal.chicken.ChickenSoundVariant; import net.minecraft.world.entity.animal.chicken.ChickenVariant; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; @@ -34,6 +35,18 @@ public void setVariant(Variant variant) { this.getHandle().setVariant(CraftVariant.bukkitToMinecraftHolder(variant)); } + @Override + public SoundVariant getSoundVariant() { + return CraftSoundVariant.minecraftHolderToBukkit(this.getHandle().getSoundVariant()); + } + + @Override + public void setSoundVariant(final SoundVariant variant) { + Preconditions.checkArgument(variant != null, "variant cannot be null"); + + this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(variant)); + } + public static class CraftVariant extends HolderableBase implements Variant { public static Variant minecraftHolderToBukkit(Holder minecraft) { @@ -44,12 +57,26 @@ public static Holder bukkitToMinecraftHolder(Variant bukkit) { return CraftRegistry.bukkitToMinecraftHolder(bukkit); } - public CraftVariant(Holder holder) { super(holder); } } + public static class CraftSoundVariant extends HolderableBase implements SoundVariant { + + public static SoundVariant minecraftHolderToBukkit(Holder minecraft) { + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.CHICKEN_SOUND_VARIANT); + } + + public static Holder bukkitToMinecraftHolder(SoundVariant bukkit) { + return CraftRegistry.bukkitToMinecraftHolder(bukkit); + } + + public CraftSoundVariant(final Holder holder) { + super(holder); + } + } + @Override public boolean isChickenJockey() { return this.getHandle().isChickenJockey(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java index e0adc2c33c26..8403fb7872e3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCow.java @@ -4,6 +4,7 @@ import io.papermc.paper.registry.HolderableBase; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.animal.cow.CowSoundVariant; import net.minecraft.world.entity.animal.cow.CowVariant; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; @@ -34,6 +35,18 @@ public void setVariant(Variant variant) { this.getHandle().setVariant(CraftVariant.bukkitToMinecraftHolder(variant)); } + @Override + public SoundVariant getSoundVariant() { + return CraftSoundVariant.minecraftHolderToBukkit(this.getHandle().getSoundVariant()); + } + + @Override + public void setSoundVariant(SoundVariant variant) { + Preconditions.checkArgument(variant != null, "variant cannot be null"); + + this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(variant)); + } + public static class CraftVariant extends HolderableBase implements Variant { public static Variant minecraftHolderToBukkit(Holder minecraft) { @@ -48,4 +61,19 @@ public CraftVariant(final Holder holder) { super(holder); } } + + public static class CraftSoundVariant extends HolderableBase implements SoundVariant { + + public static SoundVariant minecraftHolderToBukkit(Holder minecraft) { + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.COW_SOUND_VARIANT); + } + + public static Holder bukkitToMinecraftHolder(SoundVariant bukkit) { + return CraftRegistry.bukkitToMinecraftHolder(bukkit); + } + + public CraftSoundVariant(final Holder holder) { + super(holder); + } + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java index 831d710bef17..69e5088b13b7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java @@ -21,9 +21,8 @@ public net.minecraft.world.entity.Display getHandle() { @Override public Transformation getTransformation() { - com.mojang.math.Transformation nms = net.minecraft.world.entity.Display.createTransformation(this.getHandle().getEntityData()); - - return new Transformation(new Vector3f(nms.getTranslation()), new Quaternionf(nms.getLeftRotation()), new Vector3f(nms.getScale()), new Quaternionf(nms.getRightRotation())); + com.mojang.math.Transformation transformation = net.minecraft.world.entity.Display.createTransformation(this.getHandle().getEntityData()); + return new Transformation(new Vector3f(transformation.translation()), new Quaternionf(transformation.leftRotation()), new Vector3f(transformation.scale()), new Quaternionf(transformation.rightRotation())); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java index 52a5240b7a69..3cfcd01107b3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java @@ -30,14 +30,14 @@ public boolean teleportRandomly() { @Override public MaterialData getCarriedMaterial() { - BlockState blockData = this.getHandle().getCarriedBlock(); - return (blockData == null) ? Material.AIR.getNewData((byte) 0) : CraftMagicNumbers.getMaterial(blockData); + BlockState carried = this.getHandle().getCarriedBlock(); + return (carried == null) ? Material.AIR.getNewData((byte) 0) : CraftMagicNumbers.getMaterial(carried); } @Override public BlockData getCarriedBlock() { - BlockState blockData = this.getHandle().getCarriedBlock(); - return (blockData == null) ? null : CraftBlockData.fromData(blockData); + BlockState carried = this.getHandle().getCarriedBlock(); + return (carried == null) ? null : carried.asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 2a572ef0ba74..2f40476da09c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -909,7 +909,7 @@ public void setPortalCooldown(int cooldown) { @Override public Set getScoreboardTags() { - return this.getHandle().getTags(); + return this.getHandle().entityTags(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java index eacdc2467fae..ded2f19ab8bd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java @@ -26,7 +26,7 @@ public Material getMaterial() { @Override public BlockData getBlockData() { - return CraftBlockData.fromData(this.getHandle().getBlockState()); + return this.getHandle().getBlockState().asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java index 2f68d8708150..ca5974335e19 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftGuardian.java @@ -21,6 +21,7 @@ public net.minecraft.world.entity.monster.Guardian getHandle() { @Override public void setTarget(LivingEntity target) { super.setTarget(target); + target = super.getTarget(); // target might fail so update the reference // clean up laser target, when target is removed if (target == null) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index b0987314d263..ec1b31e78b55 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -21,6 +21,7 @@ import net.minecraft.server.waypoints.ServerWaypointManager; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; @@ -631,21 +632,21 @@ public T launchProjectile(Class projectile, launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle(), location.getX(), location.getY() - 0.15F, location.getZ(), true); // Paper - pass correct default to rocket for data storage & see CrossbowItem for regular launch without elytra boost // Lifted from net.minecraft.world.item.ProjectileWeaponItem.shoot - float f2 = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack int projectileSize = 1; int i = 0; - float f3 = projectileSize == 1 ? 0.0F : 2.0F * f2 / (float) (projectileSize - 1); - float f4 = (float) ((projectileSize - 1) % 2) * f3 / 2.0F; - float f5 = 1.0F; - float yaw = f4 + f5 * (float) ((i + 1) / 2) * f3; + float maxAngle = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack + float angleStep = projectileSize == 1 ? 0.0F : 2.0F * maxAngle / (float) (projectileSize - 1); + float angleOffset = (float) ((projectileSize - 1) % 2) * angleStep / 2.0F; + float direction = 1.0F; + float angle = angleOffset + direction * ((i + 1) / 2) * angleStep; // Lifted from net.minecraft.world.item.CrossbowItem.shootProjectile - Vec3 vec3 = this.getHandle().getUpVector(1.0F); - org.joml.Quaternionf quaternionf = new org.joml.Quaternionf().setAngleAxis((double)(yaw * (float) (Math.PI / 180.0)), vec3.x, vec3.y, vec3.z); - Vec3 vec32 = this.getHandle().getViewVector(1.0F); - org.joml.Vector3f vector3f = vec32.toVector3f().rotate(quaternionf); - ((FireworkRocketEntity) launch).shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F); + Vec3 upVector = this.getHandle().getUpVector(1.0F); + org.joml.Quaternionf upQuaternion = new org.joml.Quaternionf().setAngleAxis((double)(angle * (float) (Math.PI / 180.0)), upVector.x, upVector.y, upVector.z); + Vec3 viewVec = this.getHandle().getViewVector(1.0F); + org.joml.Vector3f shotVector = viewVec.toVector3f().rotate(upQuaternion); + ((FireworkRocketEntity) launch).shoot(shotVector.x(), shotVector.y(), shotVector.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F); // Paper end } @@ -677,7 +678,7 @@ public boolean hasLineOfSight(Location loc) { net.minecraft.world.phys.Vec3 start = new net.minecraft.world.phys.Vec3(this.getHandle().getX(), this.getHandle().getEyeY(), this.getHandle().getZ()); net.minecraft.world.phys.Vec3 end = new net.minecraft.world.phys.Vec3(loc.getX(), loc.getY(), loc.getZ()); - if (end.distanceToSqr(start) > 128D * 128D) { + if (end.distanceToSqr(start) > Mth.square(128.0)) { return false; // Return early if the distance is greater than 128 blocks } @@ -686,13 +687,13 @@ public boolean hasLineOfSight(Location loc) { @Override public boolean getRemoveWhenFarAway() { - return this.getHandle() instanceof Mob && !((Mob) this.getHandle()).isPersistenceRequired(); + return this.getHandle() instanceof Mob mob && !mob.isPersistenceRequired(); } @Override public void setRemoveWhenFarAway(boolean remove) { - if (this.getHandle() instanceof Mob) { - ((Mob) this.getHandle()).setPersistenceRequired(!remove); + if (this.getHandle() instanceof Mob mob) { + mob.persistenceRequired = !remove; } } @@ -703,8 +704,8 @@ public void setRemoveWhenFarAway(boolean remove) { @Override public void setCanPickupItems(boolean pickup) { - if (this.getHandle() instanceof Mob) { - ((Mob) this.getHandle()).setCanPickUpLoot(pickup); + if (this.getHandle() instanceof Mob mob) { + mob.setCanPickUpLoot(pickup); } else { this.getHandle().bukkitPickUpLoot = pickup; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java index 78149d1adc3a..adf72e8c981b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecart.java @@ -42,7 +42,7 @@ public double getMaxSpeed() { @Override public void setMaxSpeed(double speed) { - if (speed >= 0D) { + if (speed >= 0) { this.getHandle().maxSpeed = speed; } } @@ -102,8 +102,7 @@ public MaterialData getDisplayBlock() { @Override public BlockData getDisplayBlockData() { - BlockState state = this.getHandle().getDisplayBlockState(); - return CraftBlockData.fromData(state); + return this.getHandle().getDisplayBlockState().asBlockData(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java index 959fea246014..d30f9b4a8896 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java @@ -3,7 +3,9 @@ import com.google.common.base.Preconditions; import java.util.Optional; import net.kyori.adventure.util.TriState; +import net.minecraft.Optionull; import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.Entity; import org.bukkit.Sound; import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.CraftServer; @@ -66,10 +68,8 @@ public void setTarget(LivingEntity target) { } @Override - public CraftLivingEntity getTarget() { - if (this.getHandle().getTarget() == null) return null; - - return (CraftLivingEntity) this.getHandle().getTarget().getBukkitEntity(); + public LivingEntity getTarget() { + return (LivingEntity) Optionull.map(this.getHandle().getTarget(), Entity::getBukkitEntity); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java index b127a2b4b36d..b82683cf8867 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java @@ -5,6 +5,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.animal.pig.PigSoundVariant; import net.minecraft.world.entity.animal.pig.PigVariant; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -82,6 +83,18 @@ public void setVariant(Variant variant) { this.getHandle().setVariant(CraftVariant.bukkitToMinecraftHolder(variant)); } + @Override + public SoundVariant getSoundVariant() { + return CraftSoundVariant.minecraftHolderToBukkit(this.getHandle().getSoundVariant()); + } + + @Override + public void setSoundVariant(SoundVariant variant) { + Preconditions.checkArgument(variant != null, "variant cannot be null"); + + this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(variant)); + } + public static class CraftVariant extends HolderableBase implements Variant { public static Variant minecraftHolderToBukkit(Holder minecraft) { @@ -96,4 +109,19 @@ public CraftVariant(final Holder holder) { super(holder); } } + + public static class CraftSoundVariant extends HolderableBase implements SoundVariant { + + public static SoundVariant minecraftHolderToBukkit(Holder minecraft) { + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.PIG_SOUND_VARIANT); + } + + public static Holder bukkitToMinecraftHolder(SoundVariant bukkit) { + return CraftRegistry.bukkitToMinecraftHolder(bukkit); + } + + public CraftSoundVariant(final Holder holder) { + super(holder); + } + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index d86ebc4cd182..5cd042b4119d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -61,6 +61,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.chat.ResolutionContext; import net.minecraft.network.protocol.common.ClientboundClearDialogPacket; import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.network.protocol.common.ClientboundResourcePackPopPacket; @@ -95,6 +96,7 @@ import net.minecraft.network.protocol.game.ClientboundSetHealthPacket; import net.minecraft.network.protocol.game.ClientboundSetPlayerInventoryPacket; import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTimePacket; import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket; @@ -115,6 +117,8 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.util.ProblemReporter; import net.minecraft.world.InteractionHand; +import net.minecraft.world.clock.ClockNetworkState; +import net.minecraft.world.clock.WorldClock; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.ai.attributes.AttributeInstance; @@ -127,6 +131,7 @@ import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.border.BorderChangeListener; +import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.saveddata.maps.MapDecoration; import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; @@ -374,7 +379,7 @@ public InetSocketAddress getVirtualHost() { @Override public double getEyeHeight(boolean ignorePose) { if (ignorePose) { - return 1.62D; + return 1.62; } else { return this.getEyeHeight(); } @@ -775,7 +780,7 @@ public void playNote(Location loc, Instrument instrument, Note note) { if (instrumentSound == null) return; // Paper start - use correct pitch (modeled off of NoteBlock) - final net.minecraft.world.level.block.state.properties.NoteBlockInstrument noteBlockInstrument = CraftBlockData.toNMS(instrument, net.minecraft.world.level.block.state.properties.NoteBlockInstrument.class); + final net.minecraft.world.level.block.state.properties.NoteBlockInstrument noteBlockInstrument = CraftBlockData.toVanilla(instrument, net.minecraft.world.level.block.state.properties.NoteBlockInstrument.class); final float pitch = noteBlockInstrument.isTunable() ? note.getPitch() : 1.0f; // Paper end this.getHandle().connection.send(new ClientboundSoundPacket(CraftSound.bukkitToMinecraftHolder(instrumentSound), net.minecraft.sounds.SoundSource.RECORDS, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), 3.0f, pitch, this.getHandle().getRandom().nextLong())); @@ -1526,18 +1531,25 @@ public void setStatistic(Statistic statistic, EntityType entityType, int newValu } @Override - public void setPlayerTime(long time, boolean relative) { + public void setPlayerTime(long time, boolean tickTime) { this.getHandle().timeOffset = time; - this.getHandle().relativeTime = relative; + this.getHandle().relativeTime = tickTime; - if (this.getHandle().connection == null) { + final ServerLevel level = this.getHandle().level(); + if (this.getHandle().connection == null || level.dimensionType().defaultClock().isEmpty()) { return; } - final long gameTime = this.getHandle().level().getGameTime(); - final long dayTime = this.getHandle().getPlayerTime(); - final boolean tickDayTime = this.getHandle().relativeTime && this.getHandle().level().getGameRules().get(net.minecraft.world.level.gamerules.GameRules.ADVANCE_TIME); - this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSetTimePacket(gameTime, dayTime, tickDayTime)); + final long gameTime = level.getGameTime(); + final long playerClockTime = this.getHandle().getPlayerTime(); + final Holder worldClock = level.dimensionType().defaultClock().get(); + final boolean paused = !this.getHandle().relativeTime || !level.getGameRules().get(GameRules.ADVANCE_TIME) || level.clockManager().isPaused(worldClock); + final ClockNetworkState clockState = new ClockNetworkState( + playerClockTime, + level.clockManager().partialTick(worldClock), + paused ? 0.0F : level.clockManager().rate(worldClock) + ); + this.getHandle().connection.send(new ClientboundSetTimePacket(gameTime, Map.of(worldClock, clockState))); } @Override @@ -2975,7 +2987,7 @@ public void openBook(ItemStack book) { net.minecraft.world.item.ItemStack bookItem = CraftItemStack.asNMSCopy(book); ServerPlayer serverPlayer = this.getHandle(); - net.minecraft.world.item.component.WrittenBookContent.resolveForItem(bookItem, serverPlayer.createCommandSourceStack(), serverPlayer); + net.minecraft.world.item.component.WrittenBookContent.resolveForItem(bookItem, ResolutionContext.create(serverPlayer.createCommandSourceStack()), serverPlayer.registryAccess()); sendBookOpen(bookItem); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java index 4b391fdd35d4..eec4a8a2992a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java @@ -72,6 +72,6 @@ public void setBlockData(org.bukkit.block.data.BlockData data) { @Override public org.bukkit.block.data.BlockData getBlockData() { - return org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(this.getHandle().getBlockState()); + return this.getHandle().getBlockState().asBlockData(); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java index 1efb6f720f34..537b3590e036 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftTadpole.java @@ -26,11 +26,11 @@ public void setAge(int age) { @Override public void setAgeLock(boolean lock) { - this.getHandle().ageLocked = lock; + this.getHandle().setAgeLocked(lock); } @Override public boolean getAgeLock() { - return this.getHandle().ageLocked; + return this.getHandle().isAgeLocked(); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java index 22704813d84f..60edac5d0544 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java @@ -95,10 +95,7 @@ public boolean increaseLevel(int amount) { Preconditions.checkArgument(net.minecraft.world.entity.npc.villager.VillagerData.MIN_VILLAGER_LEVEL <= supposedFinalLevel && supposedFinalLevel <= net.minecraft.world.entity.npc.villager.VillagerData.MAX_VILLAGER_LEVEL, "Final level reached after the donation (%d) must be between [%d, %d]".formatted(supposedFinalLevel, net.minecraft.world.entity.npc.villager.VillagerData.MIN_VILLAGER_LEVEL, net.minecraft.world.entity.npc.villager.VillagerData.MAX_VILLAGER_LEVEL)); - it.unimi.dsi.fastutil.ints.Int2ObjectMap trades = - net.minecraft.world.entity.npc.villager.VillagerTrades.TRADES.get((this.getHandle().getVillagerData().profession().unwrapKey().orElseThrow())); - - if (trades == null || trades.isEmpty()) { + if (this.getHandle().getVillagerData().profession().value().getTrades(this.getVillagerLevel()) == null) { this.getHandle().setVillagerData(this.getHandle().getVillagerData().withLevel(supposedFinalLevel)); return false; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index cd83ca2ace1d..c6f4b3bd80d3 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -6,15 +6,6 @@ import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.block.bed.BedEnterProblem; import io.papermc.paper.connection.HorriblePlayerLoginEventHack; @@ -23,6 +14,14 @@ import io.papermc.paper.event.connection.PlayerConnectionValidateLoginEvent; import io.papermc.paper.event.entity.ItemTransportingEntityValidateTargetEvent; import io.papermc.paper.event.player.PlayerBedFailEnterEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.Connection; @@ -45,14 +44,9 @@ import net.minecraft.world.entity.Leashable; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.animal.fish.AbstractFish; -import net.minecraft.world.entity.animal.golem.AbstractGolem; import net.minecraft.world.entity.animal.Animal; -import net.minecraft.world.entity.animal.fish.WaterAnimal; +import net.minecraft.world.entity.animal.fish.AbstractFish; import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.monster.Ghast; -import net.minecraft.world.entity.monster.Monster; -import net.minecraft.world.entity.monster.Slime; import net.minecraft.world.entity.monster.illager.SpellcasterIllager; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.entity.raid.Raid; @@ -103,7 +97,6 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.CraftBlockStates; -import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.damage.CraftDamageSource; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftLivingEntity; @@ -513,16 +506,16 @@ public static BlockMultiPlaceEvent callBlockMultiPlaceEvent(ServerLevel level, n return event; } - public static BlockPlaceEvent callBlockPlaceEvent(ServerLevel level, net.minecraft.world.entity.player.Player player, InteractionHand hand, BlockState replacedSnapshot, BlockPos clickedPos) { + public static BlockPlaceEvent callBlockPlaceEvent(ServerLevel level, net.minecraft.world.entity.player.Player player, InteractionHand hand, BlockState replacedState, BlockPos clickedPos) { Player cplayer = (Player) player.getBukkitEntity(); Block clickedBlock = CraftBlock.at(level, clickedPos); - Block placedBlock = replacedSnapshot.getBlock(); + Block placedBlock = replacedState.getBlock(); boolean canBuild = CraftEventFactory.canBuild(level, cplayer, placedBlock.getX(), placedBlock.getZ()); EquipmentSlot handSlot = CraftEquipmentSlot.getHand(hand); - BlockPlaceEvent event = new BlockPlaceEvent(placedBlock, replacedSnapshot, clickedBlock, cplayer.getInventory().getItem(handSlot), cplayer, canBuild, handSlot); + BlockPlaceEvent event = new BlockPlaceEvent(placedBlock, replacedState, clickedBlock, cplayer.getInventory().getItem(handSlot), cplayer, canBuild, handSlot); event.callEvent(); return event; @@ -916,9 +909,9 @@ public static io.papermc.paper.event.entity.WaterBottleSplashEvent callWaterBott } // Paper end - Fix potions splash events - public static BlockFadeEvent callBlockFadeEvent(LevelAccessor world, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { - CraftBlockState snapshot = CraftBlockStates.getBlockState(world, pos); - snapshot.setData(state); + public static BlockFadeEvent callBlockFadeEvent(LevelAccessor level, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { + CraftBlockState snapshot = CraftBlockStates.getBlockState(level, pos); + snapshot.setBlock(state); BlockFadeEvent event = new BlockFadeEvent(snapshot.getBlock(), snapshot); Bukkit.getPluginManager().callEvent(event); @@ -927,7 +920,7 @@ public static BlockFadeEvent callBlockFadeEvent(LevelAccessor world, BlockPos po public static boolean handleMoistureChangeEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags) { CraftBlockState snapshot = CraftBlockStates.getBlockState(world, pos); - snapshot.setData(state); + snapshot.setBlock(state); MoistureChangeEvent event = new MoistureChangeEvent(snapshot.getBlock(), snapshot); if (event.callEvent()) { @@ -939,21 +932,21 @@ public static boolean handleMoistureChangeEvent(Level world, BlockPos pos, net.m public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPos up to five methods deep. - public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags) { - return handleBlockSpreadEvent(world, source, target, state, flags, false); + public static boolean handleBlockSpreadEvent(LevelAccessor level, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags) { + return handleBlockSpreadEvent(level, source, target, state, flags, false); } - public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags, boolean checkSetResult) { + public static boolean handleBlockSpreadEvent(LevelAccessor level, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags, boolean checkSetResult) { // Suppress during worldgen - if (!(world instanceof Level)) { - boolean result = world.setBlock(target, state, flags); + if (!(level instanceof Level)) { + boolean result = level.setBlock(target, state, flags); return !checkSetResult || result; } - CraftBlockState snapshot = CraftBlockStates.getBlockState(world, target); - snapshot.setData(state); + CraftBlockState snapshot = CraftBlockStates.getBlockState(level, target); + snapshot.setBlock(state); - BlockSpreadEvent event = new BlockSpreadEvent(snapshot.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), snapshot); + BlockSpreadEvent event = new BlockSpreadEvent(snapshot.getBlock(), CraftBlock.at(level, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), snapshot); if (event.callEvent()) { boolean result = snapshot.place(flags); return !checkSetResult || result; @@ -1293,7 +1286,7 @@ public static PlayerExpChangeEvent callPlayerExpChangeEvent(net.minecraft.world. public static boolean handleBlockGrowEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags) { CraftBlockState snapshot = CraftBlockStates.getBlockState(world, pos); - snapshot.setData(state); + snapshot.setBlock(state); BlockGrowEvent event = new BlockGrowEvent(snapshot.getBlock(), snapshot); if (event.callEvent()) { @@ -1305,7 +1298,7 @@ public static boolean handleBlockGrowEvent(Level world, BlockPos pos, net.minecr } public static FluidLevelChangeEvent callFluidLevelChangeEvent(Level world, BlockPos block, net.minecraft.world.level.block.state.BlockState newData) { - FluidLevelChangeEvent event = new FluidLevelChangeEvent(CraftBlock.at(world, block), CraftBlockData.fromData(newData)); + FluidLevelChangeEvent event = new FluidLevelChangeEvent(CraftBlock.at(world, block), newData.asBlockData()); world.getCraftServer().getPluginManager().callEvent(event); return event; } @@ -1347,7 +1340,7 @@ public static boolean callEntityChangeBlockEvent(Entity entity, BlockPos pos, ne public static boolean callEntityChangeBlockEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState, boolean cancelled) { Block block = CraftBlock.at(entity.level(), pos); - EntityChangeBlockEvent event = new EntityChangeBlockEvent(entity.getBukkitEntity(), block, CraftBlockData.fromData(newState)); + EntityChangeBlockEvent event = new EntityChangeBlockEvent(entity.getBukkitEntity(), block, newState.asBlockData()); event.setCancelled(cancelled); event.getEntity().getServer().getPluginManager().callEvent(event); return !event.isCancelled(); @@ -1365,17 +1358,27 @@ public static EntityTargetEvent callEntityTargetEvent(Entity entity, Entity targ return event; } + public static EntityTargetEvent.TargetReason getForgotTargetReason(Mob body, net.minecraft.world.entity.@Nullable LivingEntity previousTarget, boolean wasInvalid) { + if (previousTarget != null && !previousTarget.isAlive()) { + return EntityTargetEvent.TargetReason.TARGET_DIED; + } else if (wasInvalid || (previousTarget != null && !body.canAttack(previousTarget))) { + return EntityTargetEvent.TargetReason.TARGET_INVALID; + } else { + return EntityTargetEvent.TargetReason.FORGOT_TARGET; + } + } + public static EntityTargetLivingEntityEvent callEntityTargetLivingEvent(Entity entity, net.minecraft.world.entity.LivingEntity target, EntityTargetEvent.TargetReason reason) { EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(entity.getBukkitEntity(), (target == null) ? null : (LivingEntity) target.getBukkitEntity(), reason); entity.getBukkitEntity().getServer().getPluginManager().callEvent(event); return event; } - public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState) { // Paper + public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState) { org.bukkit.entity.Entity entity1 = entity.getBukkitEntity(); Block block = CraftBlock.at(entity.level(), pos); - EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block, newState.createCraftBlockData()); // Paper + EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block, newState.asBlockData()); entity1.getServer().getPluginManager().callEvent(event); return event; @@ -1523,7 +1526,7 @@ public static BlockRedstoneEvent callRedstoneChange(LevelAccessor level, BlockPo } public static NotePlayEvent callNotePlayEvent(Level world, BlockPos pos, NoteBlockInstrument instrument, int note) { - NotePlayEvent event = new NotePlayEvent(CraftBlock.at(world, pos), org.bukkit.Instrument.getByType((byte) instrument.ordinal()), new org.bukkit.Note(note)); + NotePlayEvent event = new NotePlayEvent(CraftBlock.at(world, pos), org.bukkit.Instrument.values()[instrument.ordinal()], new org.bukkit.Note(note)); world.getCraftServer().getPluginManager().callEvent(event); return event; } @@ -1870,11 +1873,11 @@ public static EntityBreedEvent callEntityBreedEvent(net.minecraft.world.entity.L return event; } - public static BlockPhysicsEvent callBlockPhysicsEvent(LevelAccessor world, BlockPos pos) { - org.bukkit.block.Block block = CraftBlock.at(world, pos); + public static BlockPhysicsEvent callBlockPhysicsEvent(LevelAccessor level, BlockPos pos) { + org.bukkit.block.Block block = CraftBlock.at(level, pos); BlockPhysicsEvent event = new BlockPhysicsEvent(block, block.getBlockData()); // Suppress during worldgen - if (world instanceof Level) { + if (level instanceof Level) { event.callEvent(); } return event; @@ -1921,7 +1924,7 @@ public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecr public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState state, @net.minecraft.world.level.block.Block.UpdateFlags int flags, @Nullable Entity entity, boolean checkSetResult) { CraftBlockState snapshot = CraftBlockStates.getBlockState(world, pos); - snapshot.setData(state); + snapshot.setBlock(state); BlockFormEvent event = (entity == null) ? new BlockFormEvent(snapshot.getBlock(), snapshot) : new EntityBlockFormEvent(entity.getBukkitEntity(), snapshot.getBlock(), snapshot); if (event.callEvent()) { @@ -2033,13 +2036,13 @@ public static PiglinBarterEvent callPiglinBarterEvent(net.minecraft.world.entity public static void callEntitiesLoadEvent(Level world, ChunkPos coords, List entities) { List bukkitEntities = Collections.unmodifiableList(entities.stream().map(Entity::getBukkitEntity).collect(Collectors.toList())); - EntitiesLoadEvent event = new EntitiesLoadEvent(new CraftChunk((ServerLevel) world, coords.x, coords.z), bukkitEntities); + EntitiesLoadEvent event = new EntitiesLoadEvent(new CraftChunk((ServerLevel) world, coords.x(), coords.z()), bukkitEntities); Bukkit.getPluginManager().callEvent(event); } public static void callEntitiesUnloadEvent(Level world, ChunkPos coords, List entities) { List bukkitEntities = Collections.unmodifiableList(entities.stream().map(Entity::getBukkitEntity).collect(Collectors.toList())); - EntitiesUnloadEvent event = new EntitiesUnloadEvent(new CraftChunk((ServerLevel) world, coords.x, coords.z), bukkitEntities); + EntitiesUnloadEvent event = new EntitiesUnloadEvent(new CraftChunk((ServerLevel) world, coords.x(), coords.z()), bukkitEntities); Bukkit.getPluginManager().callEvent(event); } @@ -2215,9 +2218,9 @@ public static void callEntityRemoveEvent(Entity entity, EntityRemoveEvent.Cause Bukkit.getPluginManager().callEvent(new EntityRemoveEvent(entity.getBukkitEntity(), cause)); } - public static void callPlayerUseUnknownEntityEvent(net.minecraft.world.entity.player.Player player, net.minecraft.network.protocol.game.ServerboundInteractPacket packet, InteractionHand hand, net.minecraft.world.phys.@Nullable Vec3 vector) { + public static void callPlayerUseUnknownEntityEvent(net.minecraft.world.entity.player.Player player, int entityId, boolean attack, InteractionHand hand, net.minecraft.world.phys.@Nullable Vec3 vector) { new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent( - (Player) player.getBukkitEntity(), packet.getEntityId(), packet.isAttack(), + (Player) player.getBukkitEntity(), entityId, attack, CraftEquipmentSlot.getHand(hand), vector != null ? CraftVector.toBukkit(vector) : null ).callEvent(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java index e45d3f271c71..3befaeb00289 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java @@ -107,7 +107,7 @@ public MaterialData getTypeAndData(int x, int y, int z) { @Override public BlockData getBlockData(int x, int y, int z) { - return CraftBlockData.fromData(this.getTypeId(x, y, z)); + return this.getTypeId(x, y, z).asBlockData(); } public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockState type) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java index eb39073213ff..2771961b14d4 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java @@ -39,7 +39,7 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe private static final Logger LOGGER = LogUtils.getLogger(); - private final WeakReference weakAccess; + private final WeakReference weakLevel; private final int centerChunkX; private final int centerChunkZ; // Buffer is one chunk (16 blocks), can be seen in ChunkStatus#q @@ -55,12 +55,12 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe // Prevents crash for chunks which are converting from 1.17 to 1.18 private final List outsideEntities = new ArrayList<>(); - public CraftLimitedRegion(WorldGenLevel access, ChunkPos center) { - this.weakAccess = new WeakReference<>(access); - this.centerChunkX = center.x; - this.centerChunkZ = center.z; + public CraftLimitedRegion(WorldGenLevel level, ChunkPos center) { + this.weakLevel = new WeakReference<>(level); + this.centerChunkX = center.x(); + this.centerChunkZ = center.z(); - World world = access.getMinecraftWorld().getWorld(); + World world = level.getMinecraftWorld().getWorld(); int xCenter = this.centerChunkX << 4; int zCenter = this.centerChunkZ << 4; int xMin = xCenter - this.getBuffer(); @@ -72,9 +72,8 @@ public CraftLimitedRegion(WorldGenLevel access, ChunkPos center) { } public WorldGenLevel getHandle() { - WorldGenLevel handle = this.weakAccess.get(); - - Preconditions.checkState(handle != null, "GeneratorAccessSeed no longer present, are you using it in a different tick?"); + WorldGenLevel handle = this.weakLevel.get(); + Preconditions.checkState(handle != null, "WorldGenLevel no longer present, are you using it in a different tick?"); return handle; } @@ -132,7 +131,7 @@ public void saveEntities() { } public void breakLink() { - this.weakAccess.clear(); + this.weakLevel.clear(); } @Override @@ -274,8 +273,8 @@ public void addEntityWithPassengers(net.minecraft.world.entity.Entity entity, Cr @Override public void setBlockState(int x, int y, int z, BlockState state) { BlockPos pos = new BlockPos(x, y, z); - if (!state.getBlockData().matches(getHandle().getBlockState(pos).createCraftBlockData())) { - throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).createCraftBlockData().getAsString(false)); + if (!state.getBlockData().matches(getHandle().getBlockState(pos).asBlockData())) { + throw new IllegalArgumentException("BlockData does not match! Expected " + state.getBlockData().getAsString(false) + ", got " + getHandle().getBlockState(pos).asBlockData().getAsString(false)); } try (final ProblemReporter.ScopedCollector problemReporter = new ProblemReporter.ScopedCollector( diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java index 62bcd2e9dc32..f454fe6fe317 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java @@ -2,9 +2,10 @@ import java.util.UUID; import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.storage.LevelDataAndDimensions; import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; import org.bukkit.World; +import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.WorldUUID; import org.bukkit.generator.WorldInfo; @@ -16,22 +17,20 @@ public class CraftWorldInfo implements WorldInfo { private final long seed; private final int minHeight; private final int maxHeight; - private final net.minecraft.world.flag.FeatureFlagSet enabledFeatures; // Paper - feature flag API - // Paper start + private final net.minecraft.world.flag.FeatureFlagSet enabledFeatures; private final net.minecraft.world.level.chunk.ChunkGenerator vanillaChunkGenerator; private final net.minecraft.core.RegistryAccess.Frozen registryAccess; - public CraftWorldInfo(PrimaryLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.RegistryAccess.Frozen registryAccess) { + public CraftWorldInfo(LevelDataAndDimensions.WorldDataAndGenSettings settings, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.RegistryAccess.Frozen registryAccess) { this.registryAccess = registryAccess; this.vanillaChunkGenerator = chunkGenerator; - // Paper end - this.name = worldDataServer.getLevelName(); + this.name = settings.data().getLevelName(); this.uuid = WorldUUID.getOrCreate(session.levelDirectory.path().toFile()); this.environment = environment; - this.seed = worldDataServer.worldGenOptions().seed(); + this.seed = settings.genSettings().options().seed(); this.minHeight = dimensionManager.minY(); this.maxHeight = dimensionManager.minY() + dimensionManager.height(); - this.enabledFeatures = worldDataServer.enabledFeatures(); // Paper - feature flag API + this.enabledFeatures = settings.data().enabledFeatures(); } @Override @@ -64,7 +63,6 @@ public int getMaxHeight() { return this.maxHeight; } - // Paper start @Override public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() { final net.minecraft.world.level.levelgen.RandomState randomState; @@ -77,7 +75,7 @@ public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() { } final java.util.List possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream() - .map(biome -> org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit(biome)) + .map(CraftBiome::minecraftHolderToBukkit) .toList(); return new org.bukkit.generator.BiomeProvider() { @Override @@ -92,12 +90,9 @@ public java.util.List getBiomes(final org.bukkit.generat } }; } - // Paper end - // Paper start - feature flag API @Override public java.util.Set getFeatureFlags() { return io.papermc.paper.world.flag.PaperFeatureFlagProviderImpl.fromNms(this.enabledFeatures); } - // Paper end - feature flag API } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index 73c51c66857f..02e298db604d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -118,8 +118,8 @@ public int getSeaLevel() { @Override public void createStructures(RegistryAccess registryManager, ChunkGeneratorStructureState placementCalculator, StructureManager structureAccessor, ChunkAccess chunk, StructureTemplateManager structureTemplateManager, ResourceKey dimension) { WorldgenRandom random = CustomChunkGenerator.getSeededRandom(); - int x = chunk.getPos().x; - int z = chunk.getPos().z; + int x = chunk.getPos().x(); + int z = chunk.getPos().z(); random.setSeed(Mth.getSeed(x, "should-structures".hashCode(), z) ^ this.world.getSeed()); if (this.generator.shouldGenerateStructures(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) { @@ -130,8 +130,8 @@ public void createStructures(RegistryAccess registryManager, ChunkGeneratorStruc @Override public void buildSurface(WorldGenRegion region, StructureManager structures, RandomState noiseConfig, ChunkAccess chunk) { WorldgenRandom random = CustomChunkGenerator.getSeededRandom(); - int x = chunk.getPos().x; - int z = chunk.getPos().z; + int x = chunk.getPos().x(); + int z = chunk.getPos().z(); random.setSeed(Mth.getSeed(x, "should-surface".hashCode(), z) ^ region.getSeed()); if (this.generator.shouldGenerateSurface(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) { @@ -213,7 +213,7 @@ public void buildSurface(WorldGenRegion region, StructureManager structures, Ran int tx = pos.getX(); int ty = pos.getY(); int tz = pos.getZ(); - BlockState block = craftData.getTypeId(tx, ty, tz); + BlockState block = craftData.getBlockState(tx, ty, tz); if (block.hasBlockEntity()) { BlockEntity blockEntity = ((EntityBlock) block.getBlock()).newBlockEntity(new BlockPos((x << 4) + tx, ty, (z << 4) + tz), block); @@ -226,8 +226,8 @@ public void buildSurface(WorldGenRegion region, StructureManager structures, Ran @Override public void applyCarvers(WorldGenRegion chunkRegion, long seed, RandomState noiseConfig, BiomeManager biomeAccess, StructureManager structureAccessor, ChunkAccess chunk) { WorldgenRandom random = CustomChunkGenerator.getSeededRandom(); - int x = chunk.getPos().x; - int z = chunk.getPos().z; + int x = chunk.getPos().x(); + int z = chunk.getPos().z(); random.setSeed(Mth.getSeed(x, "should-caves".hashCode(), z) ^ chunkRegion.getSeed()); if (this.generator.shouldGenerateCaves(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) { @@ -247,8 +247,8 @@ public void applyCarvers(WorldGenRegion chunkRegion, long seed, RandomState nois public CompletableFuture fillFromNoise(Blender blender, RandomState noiseConfig, StructureManager structureAccessor, ChunkAccess chunk) { CompletableFuture future = null; WorldgenRandom random = CustomChunkGenerator.getSeededRandom(); - int x = chunk.getPos().x; - int z = chunk.getPos().z; + int x = chunk.getPos().x(); + int z = chunk.getPos().z(); random.setSeed(Mth.getSeed(x, "should-noise".hashCode(), z) ^ this.world.getSeed()); if (this.generator.shouldGenerateNoise(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) { @@ -293,8 +293,8 @@ public WeightedList getMobsAt(Holder text, RandomState noiseConfig, Block @Override public void spawnOriginalMobs(WorldGenRegion region) { WorldgenRandom random = CustomChunkGenerator.getSeededRandom(); - int x = region.getCenter().x; - int z = region.getCenter().z; + int x = region.getCenter().x(); + int z = region.getCenter().z(); random.setSeed(Mth.getSeed(x, "should-mobs".hashCode(), z) ^ region.getSeed()); if (this.generator.shouldGenerateMobs(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java index b4feddacbd64..3dbf7c7957fb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java @@ -90,17 +90,17 @@ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax @Override public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(this.getTypeId(x, y, z).getBlock()); + return CraftBlockType.minecraftToBukkit(this.getBlockState(x, y, z).getBlock()); } @Override public MaterialData getTypeAndData(int x, int y, int z) { - return CraftMagicNumbers.getMaterial(this.getTypeId(x, y, z)); + return CraftMagicNumbers.getMaterial(this.getBlockState(x, y, z)); } @Override public BlockData getBlockData(int x, int y, int z) { - return CraftBlockData.fromData(this.getTypeId(x, y, z)); + return this.getBlockState(x, y, z).asBlockData(); } public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockState type) { @@ -140,7 +140,7 @@ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax } } - public BlockState getTypeId(int x, int y, int z) { + public BlockState getBlockState(int x, int y, int z) { if (x != (x & 0xf) || y < this.minHeight || y >= this.maxHeight || z != (z & 0xf)) { return Blocks.AIR.defaultBlockState(); } @@ -154,7 +154,7 @@ public BlockState getTypeId(int x, int y, int z) { @Override public byte getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(this.getTypeId(x, y, z)); + return CraftMagicNumbers.toLegacyData(this.getBlockState(x, y, z)); } private void setBlock(int x, int y, int z, BlockState type) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlastingRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlastingRecipe.java index 24edf4f02e54..ab871ccbb478 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlastingRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlastingRecipe.java @@ -26,6 +26,6 @@ public static CraftBlastingRecipe fromBukkitRecipe(BlastingRecipe recipe) { public void addToCraftingManager() { ItemStack result = this.getResult(); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.BlastingRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), this.toNMS(this.getInputChoice(), true), CraftItemStack.asNMSCopy(result), this.getExperience(), this.getCookingTime()))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.BlastingRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), this.toNMS(this.getInputChoice(), true), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(result)), this.getExperience(), this.getCookingTime()))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftCampfireRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftCampfireRecipe.java index c675facb0cae..b0309f80fe17 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftCampfireRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftCampfireRecipe.java @@ -26,6 +26,6 @@ public static CraftCampfireRecipe fromBukkitRecipe(CampfireRecipe recipe) { public void addToCraftingManager() { ItemStack result = this.getResult(); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.CampfireCookingRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), this.toNMS(this.getInputChoice(), true), CraftItemStack.asNMSCopy(result), this.getExperience(), this.getCookingTime()))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.CampfireCookingRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), this.toNMS(this.getInputChoice(), true), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(result)), this.getExperience(), this.getCookingTime()))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftComplexRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftComplexRecipe.java index 13e879ecd5dd..c8bb82bec919 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftComplexRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftComplexRecipe.java @@ -1,7 +1,6 @@ package org.bukkit.craftbukkit.inventory; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.item.crafting.CustomRecipe; import net.minecraft.world.item.crafting.RecipeHolder; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ComplexRecipe; @@ -10,9 +9,9 @@ public class CraftComplexRecipe extends CraftingRecipe implements CraftRecipe, ComplexRecipe { - private final CustomRecipe recipe; + private final net.minecraft.world.item.crafting.CraftingRecipe recipe; - public CraftComplexRecipe(NamespacedKey key, ItemStack result, CustomRecipe recipe) { + public CraftComplexRecipe(NamespacedKey key, ItemStack result, net.minecraft.world.item.crafting.CraftingRecipe recipe) { super(key, result); this.recipe = recipe; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java index 875d6793b4f3..60f2354f3ba8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java @@ -26,6 +26,6 @@ public static CraftFurnaceRecipe fromBukkitRecipe(FurnaceRecipe recipe) { public void addToCraftingManager() { ItemStack result = this.getResult(); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmeltingRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), this.toNMS(this.getInputChoice(), true), CraftItemStack.asNMSCopy(result), this.getExperience(), this.getCookingTime()))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmeltingRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), this.toNMS(this.getInputChoice(), true), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(result)), this.getExperience(), this.getCookingTime()))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java index 680468e6c16f..1e98e8e640a7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java @@ -209,19 +209,6 @@ public InventoryHolder getOwner() { return this.owner; } - @Override - public boolean canPlaceItem(int slot, ItemStack stack) { - return true; - } - - @Override - public void startOpen(ContainerUser player) { - } - - @Override - public void stopOpen(ContainerUser player) { - } - @Override public void clearContent() { this.items.clear(); @@ -242,8 +229,7 @@ public String getTitle() { @Override public boolean isEmpty() { - Iterator iterator = this.items.iterator(); - + Iterator iterator = this.items.iterator(); ItemStack itemstack; do { @@ -251,7 +237,7 @@ public boolean isEmpty() { return true; } - itemstack = (ItemStack) iterator.next(); + itemstack = iterator.next(); } while (itemstack.isEmpty()); return false; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java index 4abee7b6d922..d383c067ab73 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java @@ -8,7 +8,6 @@ import net.minecraft.commands.arguments.item.ItemParser; import net.minecraft.core.HolderSet; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; import net.minecraft.resources.Identifier; import net.minecraft.tags.EnchantmentTags; @@ -154,18 +153,9 @@ public Color getDefaultLeatherColor() { public ItemStack createItemStack(String input) throws IllegalArgumentException { try { StringReader reader = new StringReader(input); - ItemParser.ItemResult arg = new ItemParser(CraftRegistry.getMinecraftRegistry()).parse(reader); + net.minecraft.commands.arguments.item.ItemInput arg = new ItemParser(CraftRegistry.getMinecraftRegistry()).parse(reader); Preconditions.checkArgument(!reader.canRead(), "Trailing input found when parsing ItemStack: %s", input); - - Item item = arg.item().value(); - net.minecraft.world.item.ItemStack nmsItemStack = new net.minecraft.world.item.ItemStack(item); - - DataComponentPatch nbt = arg.components(); - if (nbt != null) { - nmsItemStack.applyComponents(nbt); - } - - return CraftItemStack.asCraftMirror(nmsItemStack); + return CraftItemStack.asCraftMirror(arg.createItemStack(1)); } catch (CommandSyntaxException ex) { throw new IllegalArgumentException("Could not parse ItemStack: " + input, ex); } @@ -177,27 +167,21 @@ public Material getSpawnEgg(EntityType type) { return null; } net.minecraft.world.entity.EntityType nmsType = CraftEntityType.bukkitToMinecraft(type); - Item nmsItem = SpawnEggItem.byId(nmsType); - - if (nmsItem == null) { - return null; - } - - return CraftItemType.minecraftToBukkit(nmsItem); + return SpawnEggItem.byId(nmsType).map(net.minecraft.core.Holder::value).map(CraftItemType::minecraftToBukkit).orElse(null); } @Override public ItemStack enchantItem(Entity entity, ItemStack itemStack, int level, boolean allowTreasures) { Preconditions.checkArgument(entity != null, "The entity must not be null"); - return CraftItemFactory.enchantItem(((CraftEntity) entity).getHandle().random, itemStack, level, allowTreasures); + return CraftItemFactory.enchantItem(((CraftEntity) entity).getHandle().getRandom(), itemStack, level, allowTreasures); } @Override public ItemStack enchantItem(final World world, final ItemStack itemStack, final int level, final boolean allowTreasures) { Preconditions.checkArgument(world != null, "The world must not be null"); - return CraftItemFactory.enchantItem(((CraftWorld) world).getHandle().random, itemStack, level, allowTreasures); + return CraftItemFactory.enchantItem(((CraftWorld) world).getHandle().getRandom(), itemStack, level, allowTreasures); } @Override @@ -304,8 +288,7 @@ public ItemStack getSpawnEgg0(org.bukkit.entity.EntityType type) { String typeId = type.getKey().toString(); net.minecraft.resources.Identifier typeKey = Identifier.parse(typeId); net.minecraft.world.entity.EntityType nmsType = net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getValue(typeKey); - net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); - return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror(); + return net.minecraft.world.item.SpawnEggItem.byId(nmsType).map(net.minecraft.world.item.ItemStack::new).map(net.minecraft.world.item.ItemStack::asBukkitMirror).orElse(null); } // Paper end - old getSpawnEgg API // Paper start - enchantWithLevels API diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 002682049fe8..9f35a93034bc 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -161,7 +161,7 @@ public static ItemPredicate asCriterionConditionItem(ItemStack original) { net.minecraft.world.item.ItemStack nms = CraftItemStack.asNMSCopy(original); DataComponentExactPredicate predicate = DataComponentExactPredicate.allOf(PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, nms.getComponentsPatch())); - return new ItemPredicate(Optional.of(HolderSet.direct(nms.getItemHolder())), MinMaxBounds.Ints.ANY, new DataComponentMatchers(predicate, Collections.emptyMap())); + return new ItemPredicate(Optional.of(HolderSet.direct(nms.typeHolder())), MinMaxBounds.Ints.ANY, new DataComponentMatchers(predicate, Collections.emptyMap())); } public net.minecraft.world.item.ItemStack handle; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java index ae571d4de2b4..ca567d088adf 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java @@ -181,7 +181,7 @@ public float getCompostChance() { @Override public @Nullable ItemType getCraftingRemainingItem() { - net.minecraft.world.item.ItemStack expectedItem = this.getHandle().getCraftingRemainder(); + net.minecraft.world.item.ItemStack expectedItem = this.getHandle().getCraftingRemainder().create(); return expectedItem.isEmpty() ? null : CraftItemType.minecraftToBukkitNew(expectedItem.getItem()); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java index 71c14b8c4d46..6f8f42d359ff 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java @@ -11,6 +11,7 @@ import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.MerchantOffers; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.jspecify.annotations.Nullable; public class CraftMerchantCustom implements CraftMerchant { @@ -83,7 +84,7 @@ public MerchantOffers getOffers() { // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent @Override - public void processTrade(MerchantOffer offer, @javax.annotation.Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent + public void processTrade(MerchantOffer offer, io.papermc.paper.event.player.@Nullable PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent /* Based on {@link net.minecraft.world.entity.npc.villager.AbstractVillager#processTrade(MerchantOffer, io.papermc.paper.event.player.PlayerPurchaseEvent)} */ if (getTradingPlayer() instanceof net.minecraft.server.level.ServerPlayer) { if (event == null || event.willIncreaseTradeUses()) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java index 4a4e0d629b6b..1d381afe5c2d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java @@ -140,11 +140,11 @@ public net.minecraft.world.item.trading.MerchantOffer toMinecraft() { Preconditions.checkState(!ingredients.isEmpty(), "No offered ingredients"); net.minecraft.world.item.ItemStack baseCostA = CraftItemStack.asNMSCopy(ingredients.get(0)); DataComponentExactPredicate baseCostAPredicate = DataComponentExactPredicate.allOf(PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, baseCostA.getComponentsPatch())); - this.handle.baseCostA = new ItemCost(baseCostA.getItemHolder(), baseCostA.getCount(), baseCostAPredicate, baseCostA); + this.handle.baseCostA = new ItemCost(baseCostA.typeHolder(), baseCostA.getCount(), baseCostAPredicate, baseCostA); if (ingredients.size() > 1) { net.minecraft.world.item.ItemStack costB = CraftItemStack.asNMSCopy(ingredients.get(1)); DataComponentExactPredicate costBPredicate = DataComponentExactPredicate.allOf(PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, costB.getComponentsPatch())); - this.handle.costB = Optional.of(new ItemCost(costB.getItemHolder(), costB.getCount(), costBPredicate, costB)); + this.handle.costB = Optional.of(new ItemCost(costB.typeHolder(), costB.getCount(), costBPredicate, costB)); } else { this.handle.costB = Optional.empty(); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java index 374908d448f9..2ae7fd055070 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java @@ -37,7 +37,7 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { getOrEmpty(tag, CraftMetaBundle.ITEMS).ifPresent((bundle) -> { bundle.items().forEach((item) -> { - ItemStack itemStack = CraftItemStack.asCraftMirror(item); + ItemStack itemStack = CraftItemStack.asCraftMirror(item.create()); if (!itemStack.isEmpty()) { // SPIGOT-7174 - Avoid adding air this.addItem(itemStack); @@ -64,10 +64,10 @@ void applyToItem(CraftMetaItem.Applicator tag) { super.applyToItem(tag); if (this.hasItems()) { - List list = new ArrayList<>(); + List list = new ArrayList<>(); for (ItemStack item : this.items) { - list.add(CraftItemStack.asNMSCopy(item)); + list.add(net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(item))); } tag.put(CraftMetaBundle.ITEMS, new BundleContents(list)); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java index 1d389460bddc..4be47edd63f8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java @@ -37,7 +37,7 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { super(tag, extraHandledDcts); getOrEmpty(tag, CraftMetaCrossbow.CHARGED_PROJECTILES).ifPresent((p) -> { - List items = p.getItems(); + List items = p.itemCopies(); if (items.isEmpty()) { return; } @@ -73,7 +73,7 @@ void applyToItem(CraftMetaItem.Applicator tag) { items.add(CraftItemStack.asNMSCopy(item)); } - tag.put(CraftMetaCrossbow.CHARGED_PROJECTILES, ChargedProjectiles.of(items)); + tag.put(CraftMetaCrossbow.CHARGED_PROJECTILES, ChargedProjectiles.ofNonEmpty(items)); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java index 3825cd713a42..93def2754898 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -5,14 +5,19 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; import com.mojang.logging.LogUtils; import com.mojang.serialization.DynamicOps; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.data.util.Conversions; +import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.set.RegistryKeySet; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -35,18 +40,18 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; -import java.util.SequencedSet; import java.util.Set; import java.util.StringJoiner; -import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; import javax.annotation.Nonnull; import javax.annotation.Nullable; import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -56,12 +61,10 @@ import net.minecraft.nbt.SnbtPrinterTagVisitor; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; -import net.minecraft.tags.TagKey; import net.minecraft.util.Unit; import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.AdventureModePredicate; -import net.minecraft.world.item.EitherHolder; import net.minecraft.world.item.JukeboxPlayable; import net.minecraft.world.item.JukeboxSongs; import net.minecraft.world.item.Rarity; @@ -95,6 +98,7 @@ import org.bukkit.craftbukkit.attribute.CraftAttributeMap; import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.configuration.ConfigSerializationUtil; import org.bukkit.craftbukkit.enchantments.CraftEnchantment; import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific; import org.bukkit.craftbukkit.inventory.components.CraftCustomModelDataComponent; @@ -132,6 +136,8 @@ import org.bukkit.tag.DamageTypeTags; import org.slf4j.Logger; +import static java.util.Objects.requireNonNull; + /** * Children must include the following: * @@ -291,7 +297,7 @@ DataComponentPatch build() { private boolean unbreakable; private Boolean enchantmentGlintOverride; private boolean glider; - private TagKey damageResistant; + private HolderSet damageResistant; private Integer maxStackSize; private ItemRarity rarity; private ItemStack useRemainder; @@ -484,7 +490,7 @@ protected final void updateFromPatch(DataComponentPatch tag, Set { - this.useRemainder = CraftItemStack.asCraftMirror(remainder.convertInto()); + this.useRemainder = CraftItemStack.asCraftMirror(remainder.convertInto().create()); }); CraftMetaItem.getOrEmpty(tag, CraftMetaItem.USE_COOLDOWN).ifPresent((cooldown) -> { this.useCooldown = new CraftUseCooldownComponent(cooldown); @@ -688,11 +694,11 @@ static Multimap buildModifiers(ItemAttributeModifi this.setGlider(glider); } - String damageResistant = SerializableMeta.getString(map, CraftMetaItem.DAMAGE_RESISTANT.BUKKIT, true); + Object damageResistant = SerializableMeta.getObject(Object.class, map, CraftMetaItem.DAMAGE_RESISTANT.BUKKIT, true); if (damageResistant != null) { - Tag tag = Bukkit.getTag(DamageTypeTags.REGISTRY_DAMAGE_TYPES, NamespacedKey.fromString(damageResistant), DamageType.class); - if (tag != null) { - this.setDamageResistant(tag); + HolderSet damageResistantHolderSet = ConfigSerializationUtil.getHolderSet(damageResistant, Registries.DAMAGE_TYPE); + if (damageResistantHolderSet != null) { + this.damageResistant = damageResistantHolderSet; } } @@ -998,7 +1004,7 @@ void applyToItem(CraftMetaItem.Applicator tag) { } if (this.hasUseRemainder()) { - tag.put(CraftMetaItem.USE_REMAINDER, new UseRemainder(CraftItemStack.asNMSCopy(this.useRemainder))); + tag.put(CraftMetaItem.USE_REMAINDER, new UseRemainder(net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(this.useRemainder)))); } if (this.hasUseCooldown()) { @@ -1443,7 +1449,10 @@ public boolean hasBlockData() { @Override public BlockData getBlockData(Material material) { BlockState defaultData = CraftBlockType.bukkitToMinecraft(material).defaultBlockState(); - return CraftBlockData.fromData((this.hasBlockData()) ? new BlockItemStateProperties(this.blockData).apply(defaultData) : defaultData); + if (this.blockData == null) { + return defaultData.asBlockData(); + } + return new BlockItemStateProperties(this.blockData).apply(defaultData).asBlockData(); } @Override @@ -1543,12 +1552,16 @@ public void setGlider(boolean glider) { @Override public boolean isFireResistant() { - return this.hasDamageResistant() && this.damageResistant == net.minecraft.tags.DamageTypeTags.IS_FIRE; + return this.hasDamageResistant() && this.damageResistant.unwrapKey().map(key -> key == net.minecraft.tags.DamageTypeTags.IS_FIRE).orElse(false); } @Override public void setFireResistant(boolean fireResistant) { - this.damageResistant = net.minecraft.tags.DamageTypeTags.IS_FIRE; + if (fireResistant) { + this.damageResistant = CraftRegistry.getMinecraftRegistry(Registries.DAMAGE_TYPE).getOrThrow(net.minecraft.tags.DamageTypeTags.IS_FIRE); + } else if (this.isFireResistant()) { + this.damageResistant = null; + } } @Override @@ -1558,12 +1571,26 @@ public boolean hasDamageResistant() { @Override public Tag getDamageResistant() { - return (this.hasDamageResistant()) ? Bukkit.getTag(DamageTypeTags.REGISTRY_DAMAGE_TYPES, CraftNamespacedKey.fromMinecraft(this.damageResistant.location()), DamageType.class) : null; + return this.hasDamageResistant() && this.damageResistant.unwrapKey().isPresent() ? Bukkit.getTag(DamageTypeTags.REGISTRY_DAMAGE_TYPES, CraftNamespacedKey.fromMinecraft(this.damageResistant.unwrapKey().get().location()), DamageType.class) : null; } @Override public void setDamageResistant(Tag tag) { - this.damageResistant = (tag != null) ? ((CraftDamageTag) tag).getHandle().key() : null; + this.damageResistant = (tag != null) ? CraftRegistry.getMinecraftRegistry(Registries.DAMAGE_TYPE).getOrThrow(((CraftDamageTag) tag).getHandle().key()) : null; + } + + @Override + public RegistryKeySet getDamageResistance() { + return this.damageResistant == null ? null : PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, this.damageResistant); + } + + @Override + public void setDamageResistance(RegistryKeySet types) { + if (types == null) { + this.damageResistant = null; + } else { + this.damageResistant = PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, Conversions.global().lookup(), types); + } } @Override @@ -1683,7 +1710,7 @@ public boolean hasJukeboxPlayable() { @Override public JukeboxPlayableComponent getJukeboxPlayable() { - return (this.hasJukeboxPlayable()) ? new CraftJukeboxComponent(this.jukebox) : new CraftJukeboxComponent(new JukeboxPlayable(new EitherHolder<>(JukeboxSongs.THIRTEEN))); + return (this.hasJukeboxPlayable()) ? new CraftJukeboxComponent(this.jukebox) : new CraftJukeboxComponent(new JukeboxPlayable(CraftRegistry.getMinecraftRegistry(Registries.JUKEBOX_SONG).get(JukeboxSongs.THIRTEEN).orElseThrow())); } @Override @@ -1833,18 +1860,20 @@ public String getAsComponentString() { this.applyToItem(tag); DataComponentPatch patch = tag.build(); - RegistryAccess registryAccess = CraftRegistry.getMinecraftRegistry(); - DynamicOps ops = registryAccess.createSerializationContext(NbtOps.INSTANCE); - Registry> componentTypeRegistry = registryAccess.lookupOrThrow(Registries.DATA_COMPONENT_TYPE); - + DynamicOps ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE); StringJoiner componentString = new StringJoiner(",", "[", "]"); + for (Entry, Optional> entry : patch.entrySet()) { - DataComponentType componentType = entry.getKey(); + DataComponentType type = entry.getKey(); + if (type.isTransient()) { + continue; + } + Optional componentValue = entry.getValue(); - String componentKey = componentTypeRegistry.getResourceKey(componentType).orElseThrow().identifier().toString(); + String componentKey = requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(type)).toString(); if (componentValue.isPresent()) { - net.minecraft.nbt.Tag componentValueAsNBT = (net.minecraft.nbt.Tag) ((DataComponentType) componentType).codecOrThrow().encodeStart(ops, componentValue.get()).getOrThrow(); + net.minecraft.nbt.Tag componentValueAsNBT = (net.minecraft.nbt.Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, componentValue.get()).getOrThrow(); String componentValueAsNBTString = new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(componentValueAsNBT); componentString.add(componentKey + "=" + componentValueAsNBTString); } else { @@ -2186,7 +2215,7 @@ ImmutableMap.Builder serialize(ImmutableMap.Builder Optional getOrEmpty(DataComponentPatch tag, It } protected static Optional getOrEmpty(final DataComponentPatch tag, final DataComponentType type) { - Optional result = tag.get(type); - return (result != null) ? result : Optional.empty(); + return Optional.ofNullable(tag.get(net.minecraft.core.component.DataComponentMap.EMPTY, type)); } private static class EnchantmentMap extends java.util.TreeMap { @@ -2562,7 +2590,7 @@ private static List convert final net.minecraft.core.Registry blockRegistry = CraftRegistry.getMinecraftRegistry().lookupOrThrow(net.minecraft.core.registries.Registries.BLOCK); for (final com.destroystokyo.paper.Namespaced namespaced : namespaceds) { if (namespaced instanceof final org.bukkit.NamespacedKey key) { - predicates.add(net.minecraft.advancements.criterion.BlockPredicate.Builder.block().of(blockRegistry, CraftBlockType.bukkitToMinecraft(Objects.requireNonNull(org.bukkit.Registry.MATERIAL.get(key)))).build()); + predicates.add(net.minecraft.advancements.criterion.BlockPredicate.Builder.block().of(blockRegistry, CraftBlockType.bukkitToMinecraft(requireNonNull(org.bukkit.Registry.MATERIAL.get(key)))).build()); } else if (namespaced instanceof final com.destroystokyo.paper.NamespacedTag tag) { predicates.add(net.minecraft.advancements.criterion.BlockPredicate.Builder.block().of(blockRegistry, net.minecraft.tags.TagKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(tag.getNamespace(), tag.getKey()))).build()); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java index 26f9278ef747..d18ea4eccba6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java @@ -29,8 +29,7 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst super(tag, extraHandledDcts); // Paper getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((en) -> { - en.instrument().unwrap(CraftRegistry.getMinecraftRegistry()) - .ifPresent(instrument -> this.instrument = CraftMusicInstrument.minecraftHolderToBukkit(instrument)); + this.instrument = CraftMusicInstrument.minecraftHolderToBukkit(en.instrument()); }); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java index 31da9c526135..f2895c108ed8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java @@ -52,7 +52,7 @@ public void addToCraftingManager() { Map data = Maps.transformValues(ingred, (bukkit) -> this.toNMS(bukkit, false)); ShapedRecipePattern pattern = ShapedRecipePattern.of(data, shape); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapedRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), pattern, CraftItemStack.asNMSCopy(this.getResult())))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapedRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.CraftingRecipe.CraftingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), pattern, net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(this.getResult()))))); } private static String[] replaceUndefinedIngredientsWithEmpty(String[] shape, Map ingredients) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java index 7c989318dc7a..5135bfe13ee2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java @@ -44,6 +44,6 @@ public void addToCraftingManager() { data.add(this.toNMS(i, true)); } - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.CraftingRecipe.CraftingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(this.getResult())), data))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java index fd4297be2565..cad46393153d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTransformRecipe.java @@ -2,7 +2,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.item.crafting.TransmuteResult; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.RecipeChoice; @@ -31,10 +30,11 @@ public void addToCraftingManager() { ItemStack result = this.getResult(); final net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(result); final net.minecraft.world.item.crafting.SmithingTransformRecipe recipe = new net.minecraft.world.item.crafting.SmithingTransformRecipe( + new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), this.toNMSOptional(this.getTemplate(), false), this.toNMS(this.getBase(), false), this.toNMSOptional(this.getAddition(), false), - new TransmuteResult(nmsStack.getItemHolder(), nmsStack.getCount(), nmsStack.getComponentsPatch()) + new net.minecraft.world.item.ItemStackTemplate(nmsStack.typeHolder(), nmsStack.getCount(), nmsStack.getComponentsPatch()) , this.willCopyDataComponents() ); MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), recipe)); // Paper - Option to prevent data components copy diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java index 868d6dce5afe..961403e5ff50 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmithingTrimRecipe.java @@ -30,6 +30,7 @@ public static CraftSmithingTrimRecipe fromBukkitRecipe(SmithingTrimRecipe recipe @Override public void addToCraftingManager() { final net.minecraft.world.item.crafting.SmithingTrimRecipe recipe = new net.minecraft.world.item.crafting.SmithingTrimRecipe( + new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), this.toNMS(this.getTemplate(), false), this.toNMS(this.getBase(), false), this.toNMS(this.getAddition(), false), diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmokingRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmokingRecipe.java index 2b5738399741..d640cb9472ef 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmokingRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftSmokingRecipe.java @@ -26,6 +26,6 @@ public static CraftSmokingRecipe fromBukkitRecipe(SmokingRecipe recipe) { public void addToCraftingManager() { ItemStack result = this.getResult(); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmokingRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), this.toNMS(this.getInputChoice(), true), CraftItemStack.asNMSCopy(result), this.getExperience(), this.getCookingTime()))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.SmokingRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), this.toNMS(this.getInputChoice(), true), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(result)), this.getExperience(), this.getCookingTime()))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftStonecuttingRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftStonecuttingRecipe.java index 723701283fb9..834cde0917ad 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftStonecuttingRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftStonecuttingRecipe.java @@ -25,6 +25,6 @@ public static CraftStonecuttingRecipe fromBukkitRecipe(StonecuttingRecipe recipe public void addToCraftingManager() { ItemStack result = this.getResult(); - MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.StonecutterRecipe(this.getGroup(), this.toNMS(this.getInputChoice(), true), CraftItemStack.asNMSCopy(result)))); + MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.StonecutterRecipe(new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), this.toNMS(this.getInputChoice(), true), net.minecraft.world.item.ItemStackTemplate.fromNonEmptyStack(CraftItemStack.asNMSCopy(result))))); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftTransmuteRecipe.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftTransmuteRecipe.java index 76716d066550..78c9ffd58228 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftTransmuteRecipe.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftTransmuteRecipe.java @@ -4,7 +4,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.item.crafting.TransmuteResult; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.RecipeChoice; @@ -31,11 +30,14 @@ public void addToCraftingManager() { final ItemStack unwrappedInternalStack = CraftItemStack.unwrap(this.getResult()); MinecraftServer.getServer().getRecipeManager().addRecipe( new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), - new net.minecraft.world.item.crafting.TransmuteRecipe(this.getGroup(), - CraftRecipe.getCategory(this.getCategory()), + new net.minecraft.world.item.crafting.TransmuteRecipe( + new net.minecraft.world.item.crafting.Recipe.CommonInfo(true), + new net.minecraft.world.item.crafting.CraftingRecipe.CraftingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()), this.toNMS(this.getInput(), true), this.toNMS(this.getMaterial(), true), - new TransmuteResult(unwrappedInternalStack.getItemHolder(), unwrappedInternalStack.getCount(), unwrappedInternalStack.getComponentsPatch()) + net.minecraft.world.item.crafting.TransmuteRecipe.DEFAULT_MATERIAL_COUNT, + new net.minecraft.world.item.ItemStackTemplate(unwrappedInternalStack.typeHolder(), unwrappedInternalStack.getCount(), unwrappedInternalStack.getComponentsPatch()) + , false ) ) ); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java index 9db372844211..093e1dbb3d92 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java @@ -10,8 +10,8 @@ import net.minecraft.core.HolderSet; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.equipment.EquipmentAssets; import net.minecraft.world.item.equipment.Equippable; @@ -50,7 +50,8 @@ public CraftEquippableComponent(Map map) { Sound equipSound = null; String equipSoundKey = SerializableMeta.getString(map, "equip-sound", true); if (equipSoundKey != null) { - equipSound = Registry.SOUNDS.get(NamespacedKey.fromString(equipSoundKey)); + NamespacedKey key = NamespacedKey.fromString(equipSoundKey); + equipSound = key == null ? null : Registry.SOUNDS.get(key); } String model = SerializableMeta.getString(map, "model", true); @@ -67,16 +68,25 @@ public CraftEquippableComponent(Map map) { Boolean damageOnHurt = SerializableMeta.getObject(Boolean.class, map, "damage-on-hurt", true); Boolean equipOnInteract = SerializableMeta.getObject(Boolean.class, map, "equip-on-interact", true); + Boolean canBeSheared = SerializableMeta.getObject(Boolean.class, map, "can-be-sheared", true); + Sound shearingSound = null; + String shearingSoundKey = SerializableMeta.getString(map, "shearing-sound", true); + if (shearingSoundKey != null) { + NamespacedKey key = NamespacedKey.fromString(shearingSoundKey); + shearingSound = key == null ? null : Registry.SOUNDS.get(key); + } + this.handle = new Equippable(slot, - (equipSound != null) ? CraftSound.bukkitToMinecraftHolder(equipSound) : SoundEvents.ARMOR_EQUIP_GENERIC, - Optional.ofNullable(model).map(Identifier::parse).map((k) -> ResourceKey.create(EquipmentAssets.ROOT_ID, k)), - Optional.ofNullable(cameraOverlay).map(Identifier::parse), - Optional.ofNullable(allowedEntities), - (dispensable != null) ? dispensable : true, - (swappable != null) ? swappable : true, - (damageOnHurt != null) ? damageOnHurt : true, - (equipOnInteract != null) ? equipOnInteract : false, - false, BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.SHEARS_SNIP) // TODO - 1.21.6 + equipSound != null ? CraftSound.bukkitToMinecraftHolder(equipSound) : SoundEvents.ARMOR_EQUIP_GENERIC, + Optional.ofNullable(model).map(Identifier::parse).map((k) -> ResourceKey.create(EquipmentAssets.ROOT_ID, k)), + Optional.ofNullable(cameraOverlay).map(Identifier::parse), + Optional.ofNullable(allowedEntities), + (dispensable != null) ? dispensable : true, + (swappable != null) ? swappable : true, + (damageOnHurt != null) ? damageOnHurt : true, + (equipOnInteract != null) ? equipOnInteract : false, + (canBeSheared != null) ? canBeSheared : false, + shearingSound != null ? CraftSound.bukkitToMinecraftHolder(shearingSound) : BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.SHEARS_SNIP) ); } @@ -102,6 +112,11 @@ public Map serialize() { result.put("swappable", this.isSwappable()); result.put("damage-on-hurt", this.isDamageOnHurt()); result.put("equip-on-interact", this.isEquipOnInteract()); + result.put("can-be-sheared", this.canBeSheared()); + Sound shearingSound = this.getShearingSound(); + if (shearingSound != null) { + result.put("shearing-sound", Registry.SOUND_EVENT.getKeyOrThrow(shearingSound).toString()); + } return result; } @@ -122,7 +137,7 @@ public void setSlot(EquipmentSlot slot) { @Override public Sound getEquipSound() { - return CraftSound.minecraftToBukkit(this.handle.equipSound().value()); + return CraftSound.minecraftHolderToBukkit(this.handle.equipSound()); } @Override @@ -158,16 +173,16 @@ public Collection getAllowedEntities() { @Override public void setAllowedEntities(EntityType entities) { this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), - (entities != null) ? Optional.of(HolderSet.direct(CraftEntityType.bukkitToMinecraftHolder(entities))) : Optional.empty(), - this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() + (entities != null) ? Optional.of(HolderSet.direct(CraftEntityType.bukkitToMinecraftHolder(entities))) : Optional.empty(), + this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() ); } @Override public void setAllowedEntities(Collection entities) { this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), - (entities != null) ? Optional.of(HolderSet.direct(entities.stream().map(CraftEntityType::bukkitToMinecraftHolder).collect(Collectors.toList()))) : Optional.empty(), - this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() + (entities != null) ? Optional.of(HolderSet.direct(entities.stream().map(CraftEntityType::bukkitToMinecraftHolder).collect(Collectors.toList()))) : Optional.empty(), + this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() ); } @@ -176,8 +191,8 @@ public void setAllowedEntities(Tag tag) { Preconditions.checkArgument(tag == null || tag instanceof CraftEntityTag, "tag must be an entity tag"); // Paper this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), - (tag != null) ? Optional.of(((CraftEntityTag) tag).getHandle()) : Optional.empty(), - this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() + (tag != null) ? Optional.of(((CraftEntityTag) tag).getHandle()) : Optional.empty(), + this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), this.handle.shearingSound() ); } @@ -221,6 +236,26 @@ public void setEquipOnInteract(final boolean equip) { this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), this.handle.allowedEntities(), this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), equip, this.handle.canBeSheared(), this.handle.shearingSound()); } + @Override + public boolean canBeSheared() { + return this.handle.canBeSheared(); + } + + @Override + public void setCanBeSheared(boolean sheared) { + this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), this.handle.allowedEntities(), this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), sheared, this.handle.shearingSound()); + } + + @Override + public Sound getShearingSound() { + return CraftSound.minecraftHolderToBukkit(this.handle.shearingSound()); + } + + @Override + public void setShearingSound(Sound sound) { + this.handle = new Equippable(this.handle.slot(), this.handle.equipSound(), this.handle.assetId(), this.handle.cameraOverlay(), this.handle.allowedEntities(), this.handle.dispensable(), this.handle.swappable(), this.handle.damageOnHurt(), this.handle.equipOnInteract(), this.handle.canBeSheared(), (sound != null) ? CraftSound.bukkitToMinecraftHolder(sound) : BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.SHEARS_SNIP)); + } + @Override public int hashCode() { int hash = 7; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftJukeboxComponent.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftJukeboxComponent.java index 616d409a8753..486471799b6b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftJukeboxComponent.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftJukeboxComponent.java @@ -3,12 +3,10 @@ import com.google.common.base.Preconditions; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Optional; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.Identifier; -import net.minecraft.world.item.EitherHolder; import net.minecraft.world.item.JukeboxPlayable; import org.bukkit.JukeboxSong; import org.bukkit.NamespacedKey; @@ -35,7 +33,9 @@ public CraftJukeboxComponent(CraftJukeboxComponent jukebox) { public CraftJukeboxComponent(Map map) { String song = SerializableMeta.getObject(String.class, map, "song", false); - this.handle = new JukeboxPlayable(new EitherHolder<>(ResourceKey.create(Registries.JUKEBOX_SONG, Identifier.parse(song)))); + final net.minecraft.core.Registry registry = CraftRegistry.getMinecraftRegistry(Registries.JUKEBOX_SONG); + final Holder.Reference holder = registry.get(ResourceKey.create(Registries.JUKEBOX_SONG, Identifier.parse(song))).orElseThrow(); + this.handle = new JukeboxPlayable(holder); } @Override @@ -51,27 +51,28 @@ public JukeboxPlayable getHandle() { @Override public JukeboxSong getSong() { - Optional> song = this.handle.song().unwrap(CraftRegistry.getMinecraftRegistry()); - return song.map(CraftJukeboxSong::minecraftHolderToBukkit).orElse(null); + return CraftJukeboxSong.minecraftHolderToBukkit(this.handle.song()); } @Override public NamespacedKey getSongKey() { - return CraftNamespacedKey.fromMinecraft(this.handle.song().key().orElseThrow().identifier()); + return CraftNamespacedKey.fromMinecraft(this.handle.song().unwrapKey().orElseThrow().identifier()); } @Override public void setSong(JukeboxSong song) { Preconditions.checkArgument(song != null, "song cannot be null"); - this.handle = new JukeboxPlayable(new EitherHolder<>(CraftJukeboxSong.bukkitToMinecraftHolder(song))); + this.handle = new JukeboxPlayable(CraftJukeboxSong.bukkitToMinecraftHolder(song)); } @Override public void setSongKey(NamespacedKey song) { Preconditions.checkArgument(song != null, "song cannot be null"); - this.handle = new JukeboxPlayable(new EitherHolder<>(ResourceKey.create(Registries.JUKEBOX_SONG, CraftNamespacedKey.toMinecraft(song)))); + final net.minecraft.core.Registry registry = CraftRegistry.getMinecraftRegistry(Registries.JUKEBOX_SONG); + final Holder.Reference holder = registry.get(ResourceKey.create(Registries.JUKEBOX_SONG, CraftNamespacedKey.toMinecraft(song))).orElseThrow(); + this.handle = new JukeboxPlayable(holder); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java index fc24964d8921..883a92b134da 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java @@ -47,8 +47,8 @@ public final class CraftLegacy { private static final Set whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing")); private static final Map materialToItem = new HashMap<>(16384); private static final Map itemToMaterial = new HashMap<>(1024); - private static final Map materialToData = new HashMap<>(4096); - private static final Map dataToMaterial = new HashMap<>(4096); + private static final Map materialToState = new HashMap<>(4096); + private static final Map stateToMaterial = new HashMap<>(4096); private static final Map materialToBlock = new HashMap<>(4096); private static final Map blockToMaterial = new HashMap<>(1024); @@ -81,7 +81,7 @@ public static MaterialData toLegacyData(Material material, boolean itemPriority) BlockState state = block.defaultBlockState(); // Try exact match first - mappedData = CraftLegacy.dataToMaterial.get(state); + mappedData = CraftLegacy.stateToMaterial.get(state); // Fallback to any block if (mappedData == null) { mappedData = CraftLegacy.blockToMaterial.get(block); @@ -104,7 +104,7 @@ public static BlockState fromLegacyData(Material material, byte data) { MaterialData materialData = new MaterialData(material, data); // Try exact match first - BlockState converted = CraftLegacy.materialToData.get(materialData); + BlockState converted = CraftLegacy.materialToState.get(materialData); if (converted != null) { return converted; } @@ -133,7 +133,7 @@ public static Item fromLegacyData(Material material, short data) { // Fallback to matching block if (material.isBlock()) { // Try exact match first - BlockState converted = CraftLegacy.materialToData.get(materialData); + BlockState converted = CraftLegacy.materialToState.get(materialData); if (converted != null) { return converted.getBlock().asItem(); } @@ -161,7 +161,7 @@ public static MaterialData toLegacy(BlockState state) { MaterialData mappedData; // Try exact match first - mappedData = CraftLegacy.dataToMaterial.get(state); + mappedData = CraftLegacy.stateToMaterial.get(state); // Fallback to any block if (mappedData == null) { mappedData = CraftLegacy.blockToMaterial.get(state.getBlock()); @@ -200,7 +200,7 @@ public static Material fromLegacy(MaterialData materialData, boolean itemPriorit if (mappedData == null) { // Try exact match first - BlockState iblock = CraftLegacy.materialToData.get(materialData); + BlockState iblock = CraftLegacy.materialToState.get(materialData); if (iblock != null) { mappedData = CraftMagicNumbers.getMaterial(iblock.getBlock()); } @@ -342,25 +342,25 @@ public static void init() { if (block == null) { continue; } - BlockState blockData = block.defaultBlockState(); - StateDefinition states = block.getStateDefinition(); + BlockState state = block.defaultBlockState(); + StateDefinition def = block.getStateDefinition(); - Optional propMap = blockTag.getElement("Properties").result(); - if (propMap.isPresent()) { - CompoundTag properties = propMap.get(); - for (String dataKey : properties.keySet()) { - Property state = states.getProperty(dataKey); + Optional propertiesTag = blockTag.getElement("Properties").result(); + if (propertiesTag.isPresent()) { + CompoundTag properties = propertiesTag.get(); + for (String propertyName : properties.keySet()) { + Property property = def.getProperty(propertyName); - if (state == null) { - Preconditions.checkArgument(whitelistedStates.contains(dataKey), "No state for %s", dataKey); + if (property == null) { + Preconditions.checkArgument(whitelistedStates.contains(propertyName), "No property for %s", propertyName); continue; } - Preconditions.checkState(properties.getString(dataKey).isPresent(), "Empty data string"); - Optional opt = state.getValue(properties.getStringOr(dataKey, "")); - Preconditions.checkArgument(opt.isPresent(), "No state value %s for %s", properties.getString(dataKey), dataKey); + Preconditions.checkState(properties.getString(propertyName).isPresent(), "Empty data string"); + Optional opt = property.getValue(properties.getStringOr(propertyName, "")); + Preconditions.checkArgument(opt.isPresent(), "No state value %s for %s", properties.getString(propertyName), propertyName); - blockData = blockData.setValue(state, (Comparable) opt.get()); + state = state.setValue(property, (Comparable) opt.get()); } } @@ -368,9 +368,9 @@ public static void init() { continue; } - materialToData.put(matData, blockData); - if (!dataToMaterial.containsKey(blockData)) { - dataToMaterial.put(blockData, matData); + materialToState.put(matData, state); + if (!stateToMaterial.containsKey(state)) { + stateToMaterial.put(state, matData); } materialToBlock.put(matData, block); @@ -413,13 +413,13 @@ public static void init() { LEGACY_ELYTRA -> 1; default -> 16; }; - // Manually do oldold spawn eggs + // Manually do old spawn eggs if (material == Material.LEGACY_MONSTER_EGG) { - maxData = 121; // Vilager + 1 + maxData = 121; // Villager + 1 } for (byte data = 0; data < maxData; data++) { - // Manually skip invalid oldold spawn + // Manually skip invalid old spawn if (material == Material.LEGACY_MONSTER_EGG /*&& data != 0 && EntityType.fromId(data) == null*/) { // Mojang broke 18w19b continue; } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java index 9bc8055c3632..a76e89c12afd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java @@ -24,7 +24,6 @@ import org.bukkit.block.DecoratedPot; import org.bukkit.block.Jukebox; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.inventory.CraftItemType; import org.bukkit.craftbukkit.legacy.reroute.InjectPluginVersion; import org.bukkit.craftbukkit.legacy.reroute.RerouteStatic; @@ -252,7 +251,7 @@ public static Set getBarterList(Piglin piglin, @InjectPluginVersion Ap @Deprecated public static void sendBlockChange(Player player, Location location, Material material, byte data) { - player.sendBlockChange(location, CraftBlockData.fromData(CraftMagicNumbers.getBlock(material, data))); + player.sendBlockChange(location, CraftMagicNumbers.getBlock(material, data).asBlockData()); } public static Material getSteerMaterial(Steerable steerable, @InjectPluginVersion ApiVersion version) { @@ -573,7 +572,7 @@ public static Set getValues(Tag tag, @InjectPluginVersio @Deprecated public static FallingBlock spawnFallingBlock(World world, Location location, Material material, byte data) { - return world.spawnFallingBlock(location, CraftBlockData.fromData(CraftMagicNumbers.getBlock(material, data))); + return world.spawnFallingBlock(location, CraftMagicNumbers.getBlock(material, data).asBlockData()); } public static ToolComponent.ToolRule addRule(ToolComponent toolComponent, Material block, Float speed, Boolean correctForDrops) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java index 4881e366c8d4..6748e1b45b5e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java @@ -61,7 +61,7 @@ public NamespacedKey getKey() { @Override public double getDurationModifier() { - return 1.0D; + return 1.0; } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java index 4d4c7861323a..30a11ae7e872 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java @@ -6,6 +6,8 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.yggdrasil.ProfileResult; +import com.mojang.datafixers.util.Either; +import io.papermc.paper.profile.MutablePropertyMap; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; @@ -15,12 +17,9 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import com.mojang.datafixers.util.Either; -import io.papermc.paper.profile.MutablePropertyMap; -import net.minecraft.util.Util; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.players.NameAndId; +import net.minecraft.util.Util; import net.minecraft.world.entity.player.PlayerSkin; import net.minecraft.world.item.component.ResolvableProfile; import org.apache.commons.lang3.StringUtils; @@ -38,24 +37,6 @@ @SerializableAs("PlayerProfile") public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile, com.destroystokyo.paper.profile.PlayerProfile { // Paper - public static GameProfile validateSkullProfile(GameProfile gameProfile) { - // The GameProfile needs to contain either both a uuid and textures, or a name. - // The GameProfile always has a name or a uuid, so checking if it has a name is sufficient. - boolean isValidSkullProfile = (gameProfile.name() != null) - || gameProfile.properties().containsKey(CraftPlayerTextures.PROPERTY_NAME); - Preconditions.checkArgument(isValidSkullProfile, "The skull profile is missing a name or textures!"); - Preconditions.checkArgument(gameProfile.name().length() <= 16, "The name of the profile is longer than 16 characters"); - Preconditions.checkArgument(net.minecraft.util.StringUtil.isValidPlayerName(gameProfile.name()), "The name of the profile contains invalid characters: %s", gameProfile.name()); - final PropertyMap properties = gameProfile.properties(); - Preconditions.checkArgument(properties.size() <= 16, "The profile contains more than 16 properties"); - for (final Property property : properties.values()) { - Preconditions.checkArgument(property.name().length() <= 64, "The name of a property is longer than 64 characters"); - Preconditions.checkArgument(property.value().length() <= Short.MAX_VALUE, "The value of a property is longer than 32767 characters"); - Preconditions.checkArgument(property.signature() == null || property.signature().length() <= 1024, "The signature of a property is longer than 1024 characters"); - } - return gameProfile; - } - public static @Nullable Property getProperty(GameProfile profile, String propertyName) { return Iterables.getFirst(profile.properties().get(propertyName), null); } @@ -213,23 +194,11 @@ public String toString() { builder.append(", name="); builder.append(this.getName()); builder.append(", properties="); - builder.append(CraftPlayerProfile.toString(this.properties)); + builder.append(this.properties); builder.append("]"); return builder.toString(); } - public static String toString(PropertyMap propertyMap) { - StringBuilder builder = new StringBuilder(); - builder.append("{"); - propertyMap.asMap().forEach((propertyName, properties) -> { - builder.append(propertyName); - builder.append("="); - builder.append(properties.stream().map(CraftProfileProperty::toString).collect(Collectors.joining(",", "[", "]"))); - }); - builder.append("}"); - return builder.toString(); - } - @Override public boolean equals(Object obj) { if (this == obj) return true; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftProfileProperty.java b/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftProfileProperty.java index 41dd3a79ba6e..c1ae3b8d9ffb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftProfileProperty.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/profile/CraftProfileProperty.java @@ -83,19 +83,6 @@ public static String encodePropertyValue(JsonObject propertyValue, JsonFormatter return Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8)); } - public static String toString(Property property) { - StringBuilder builder = new StringBuilder(); - builder.append("{"); - builder.append("name="); - builder.append(property.name()); - builder.append(", value="); - builder.append(property.value()); - builder.append(", signature="); - builder.append(property.signature()); - builder.append("}"); - return builder.toString(); - } - public static int hashCode(Property property) { int result = 1; result = 31 * result + Objects.hashCode(property.name()); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructure.java b/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructure.java index 8065aedbee7f..bc822fd99ede 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructure.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructure.java @@ -35,7 +35,7 @@ import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.craftbukkit.util.CraftStructureTransformer; import org.bukkit.craftbukkit.util.RandomSourceWrapper; -import org.bukkit.craftbukkit.util.TransformerGeneratorAccess; +import org.bukkit.craftbukkit.util.TransformerLevelAccessor; import org.bukkit.entity.Entity; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.structure.Palette; @@ -100,12 +100,12 @@ public void place(RegionAccessor regionAccessor, BlockVector location, boolean i BlockPos pos = CraftBlockVector.toBlockPosition(location); WorldGenLevel handle = ((CraftRegionAccessor) regionAccessor).getHandle(); - TransformerGeneratorAccess access = new TransformerGeneratorAccess(); - access.setDelegate(handle); - access.setStructureTransformer(new CraftStructureTransformer(handle, new ChunkPos(pos), blockTransformers, entityTransformers)); + TransformerLevelAccessor accessor = new TransformerLevelAccessor(); + accessor.setDelegate(handle); + accessor.setStructureTransformer(new CraftStructureTransformer(handle, ChunkPos.containing(pos), blockTransformers, entityTransformers)); - this.structure.placeInWorld(access, pos, pos, definedstructureinfo, randomSource, Block.UPDATE_CLIENTS); - access.getStructureTransformer().discard(); + this.structure.placeInWorld(accessor, pos, pos, definedstructureinfo, randomSource, Block.UPDATE_CLIENTS); + accessor.getStructureTransformer().discard(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructureManager.java b/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructureManager.java index 5cdc356f7288..112fc3a44503 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructureManager.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/structure/CraftStructureManager.java @@ -19,6 +19,7 @@ import net.minecraft.resources.Identifier; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import net.minecraft.world.level.levelgen.structure.templatesystem.loader.TemplateSource; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.structure.Structure; @@ -58,10 +59,8 @@ public Structure getStructure(NamespacedKey structureKey) { public Structure loadStructure(NamespacedKey structureKey, boolean register) { Identifier minecraftKey = this.createAndValidateMinecraftStructureKey(structureKey); - Optional structure = this.structureManager.structureRepository.get(minecraftKey); - structure = structure == null ? Optional.empty() : structure; - structure = structure.isPresent() ? structure : this.structureManager.loadFromGenerated(minecraftKey); - structure = structure.isPresent() ? structure : this.structureManager.loadFromResource(minecraftKey); + Optional structure = this.structureManager.structureRepository.getOrDefault(minecraftKey, Optional.empty()) + .or(() -> this.structureManager.tryLoad(minecraftKey)); if (register) { this.structureManager.structureRepository.put(minecraftKey, structure); @@ -124,14 +123,14 @@ public void deleteStructure(NamespacedKey structureKey, boolean unregister) thro if (unregister) { this.structureManager.structureRepository.remove(key); } - Path path = this.structureManager.createAndValidatePathToGeneratedStructure(key, ".nbt"); + Path path = this.structureManager.worldTemplates().createAndValidatePathToStructure(key, StructureTemplateManager.WORLD_STRUCTURE_LISTER); Files.deleteIfExists(path); } @Override public File getStructureFile(NamespacedKey structureKey) { Identifier minecraftKey = this.createAndValidateMinecraftStructureKey(structureKey); - return this.structureManager.createAndValidatePathToGeneratedStructure(minecraftKey, ".nbt").toFile(); + return this.structureManager.worldTemplates().createAndValidatePathToStructure(minecraftKey, StructureTemplateManager.WORLD_STRUCTURE_LISTER).toFile(); } @Override @@ -146,7 +145,7 @@ public Structure loadStructure(File file) throws IOException { public Structure loadStructure(InputStream inputStream) throws IOException { Preconditions.checkArgument(inputStream != null, "inputStream cannot be null"); - return new CraftStructure(this.structureManager.readStructure(inputStream), this.registry); + return new CraftStructure(this.structureManager.resourceManagerSource.readStructure(TemplateSource.readStructure(inputStream)), this.registry); } @Override @@ -183,6 +182,6 @@ private Identifier createAndValidateMinecraftStructureKey(NamespacedKey structur @Override public Structure copy(Structure structure) { Preconditions.checkArgument(structure != null, "Structure cannot be null"); - return new CraftStructure(this.structureManager.readStructure(((CraftStructure) structure).getHandle().save(new CompoundTag())), this.registry); + return new CraftStructure(this.structureManager.resourceManagerSource.readStructure(((CraftStructure) structure).getHandle().save(new CompoundTag())), this.registry); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftEntityTag.java b/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftEntityTag.java index 4270b771ff15..6dec42b91702 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftEntityTag.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftEntityTag.java @@ -16,7 +16,7 @@ public CraftEntityTag(Registry> registr @Override public boolean isTagged(EntityType entity) { - return CraftEntityType.bukkitToMinecraft(entity).is(this.tag); + return CraftEntityType.bukkitToMinecraft(entity).builtInRegistryHolder().is(this.tag); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java index 989b2f751a59..dcd668fedc37 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java @@ -4,6 +4,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.core.BlockPos; @@ -12,17 +13,20 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.storage.LevelData; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.CraftBlockStates; -public class BlockStateListPopulator extends DummyGeneratorAccess { +public class BlockStateListPopulator extends DummyLevelAccessor { private final LevelAccessor level; private final Map blocks = new LinkedHashMap<>(); @@ -52,37 +56,37 @@ public BlockEntity getBlockEntity(BlockPos pos) { } @Override - public boolean setBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState state, @Block.UpdateFlags int flags, int recursionLeft) { + public boolean setBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) { pos = pos.immutable(); // remove first to keep last updated order this.blocks.remove(pos); final BlockEntity newBlockEntity; - if (state.getBlock() instanceof EntityBlock entityBlock) { + if (blockState.getBlock() instanceof EntityBlock entityBlock) { // based on LevelChunk#setBlockState BlockEntity currentBlockEntity = this.getBlockEntity(pos); - if (currentBlockEntity != null && currentBlockEntity.isValidBlockState(state)) { + if (currentBlockEntity != null && currentBlockEntity.isValidBlockState(blockState)) { newBlockEntity = currentBlockEntity; // previous block entity is still valid for this block state - currentBlockEntity.setBlockState(state); + currentBlockEntity.setBlockState(blockState); } else { - newBlockEntity = entityBlock.newBlockEntity(pos, state); // create a new one when the block change + newBlockEntity = entityBlock.newBlockEntity(pos, blockState); // create a new one when the block change } } else { newBlockEntity = null; } - this.blocks.put(pos, new CapturedBlock(state, flags, newBlockEntity)); + this.blocks.put(pos, new CapturedBlock(blockState, updateFlags, newBlockEntity)); return true; } @Override - public boolean destroyBlock(BlockPos pos, boolean dropBlock, Entity entity, int recursionLeft) { + public boolean destroyBlock(BlockPos pos, boolean dropResources, Entity breaker, int updateLimit) { net.minecraft.world.level.block.state.BlockState blockState = this.getBlockState(pos); if (blockState.isAir()) { return false; } - this.setBlock(pos, blockState.getFluidState().createLegacyBlock(), Block.UPDATE_ALL, recursionLeft); // capture block without the event + this.setBlock(pos, blockState.getFluidState().createLegacyBlock(), Block.UPDATE_ALL, updateLimit); // capture block without the event return true; } @@ -104,15 +108,15 @@ private void iterateSnapshots(Consumer callback) { } public void placeBlocks() { - this.placeSomeBlocks($ -> true); + this.placeSomeBlocks(_ -> true); } public void placeSomeBlocks(Predicate filter) { - this.placeSomeBlocks($ -> {}, filter); + this.placeSomeBlocks(_ -> {}, filter); } public void placeBlocks(Consumer beforeRun) { - this.placeSomeBlocks(beforeRun, $ -> true); + this.placeSomeBlocks(beforeRun, _ -> true); } public void placeSomeBlocks(Consumer beforeRun, Predicate filter) { @@ -151,13 +155,13 @@ public int getHeight() { } @Override - public boolean isStateAtPosition(BlockPos pos, Predicate state) { - return state.test(this.getBlockState(pos)); + public boolean isStateAtPosition(BlockPos pos, Predicate predicate) { + return predicate.test(this.getBlockState(pos)); } @Override - public boolean isFluidAtPosition(BlockPos pos, Predicate state) { - return state.test(this.getFluidState(pos)); + public boolean isFluidAtPosition(BlockPos pos, Predicate predicate) { + return predicate.test(this.getFluidState(pos)); } @Override @@ -188,28 +192,28 @@ public RandomSource getRandom() { } @Override - public java.util.Optional getBlockEntity(BlockPos pos, net.minecraft.world.level.block.entity.BlockEntityType type) { + public Optional getBlockEntity(BlockPos pos, BlockEntityType type) { BlockEntity blockEntity = this.getBlockEntity(pos); - return blockEntity != null && blockEntity.getType() == type ? (java.util.Optional) java.util.Optional.of(blockEntity) : java.util.Optional.empty(); + return blockEntity != null && blockEntity.getType() == type ? Optional.of((T) blockEntity) : Optional.empty(); } @Override - public BlockPos getHeightmapPos(net.minecraft.world.level.levelgen.Heightmap.Types heightmapType, BlockPos pos) { - return this.level.getHeightmapPos(heightmapType, pos); + public BlockPos getHeightmapPos(Heightmap.Types type, BlockPos pos) { + return this.level.getHeightmapPos(type, pos); } @Override - public int getHeight(net.minecraft.world.level.levelgen.Heightmap.Types heightmapType, int x, int z) { - return this.level.getHeight(heightmapType, x, z); + public int getHeight(Heightmap.Types type, int x, int z) { + return this.level.getHeight(type, x, z); } @Override - public int getRawBrightness(BlockPos pos, int amount) { - return this.level.getRawBrightness(pos, amount); + public int getRawBrightness(BlockPos pos, int darkening) { + return this.level.getRawBrightness(pos, darkening); } @Override - public int getBrightness(net.minecraft.world.level.LightLayer lightType, BlockPos pos) { - return this.level.getBrightness(lightType, pos); + public int getBrightness(LightLayer layer, BlockPos pos) { + return this.level.getBrightness(layer, pos); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java index cfba954cc65c..c103a31c14b8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -135,24 +135,13 @@ public List getReroutes() { // Paper start - Plugin rewrites private static final String CB_PACKAGE_PREFIX = "org/bukkit/".concat("craftbukkit/"); - private static final String LEGACY_CB_PACKAGE_PREFIX = CB_PACKAGE_PREFIX + io.papermc.paper.util.MappingEnvironment.LEGACY_CB_VERSION + "/"; private static String runtimeCbPkgPrefix() { - if (io.papermc.paper.util.MappingEnvironment.reobf()) { - return LEGACY_CB_PACKAGE_PREFIX; - } return CB_PACKAGE_PREFIX; } @Nonnull private static String getOriginalOrRewrite(@Nonnull String original) { - // Relocation is applied in reobf, and when mappings are present they handle the relocation - if (!io.papermc.paper.util.MappingEnvironment.reobf() && !io.papermc.paper.util.MappingEnvironment.hasMappings()) { - if (original.contains(LEGACY_CB_PACKAGE_PREFIX)) { - original = original.replace(LEGACY_CB_PACKAGE_PREFIX, CB_PACKAGE_PREFIX); - } - } - return original; } // Paper end - Plugin rewrites @@ -226,16 +215,12 @@ public byte[] convert(byte[] b, final String pluginName, final ApiVersion plugin ClassReader cr = new ClassReader(b); ClassWriter cw = new ClassWriter(cr, 0); - ClassVisitor visitor = cw; - - visitor = io.papermc.paper.pluginremap.reflect.ReflectionRemapper.visitor(visitor); // Paper - Map renames = new HashMap<>(RENAMES); if (pluginVersion.isOlderThan(ApiVersion.ABSTRACT_COW)) { renames.put("org/bukkit/entity/Cow", "org/bukkit/entity/AbstractCow"); } - cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, visitor) { + cr.accept(new ClassRemapper(new ClassVisitor(Opcodes.ASM9, cw) { final Set rerouteMethodData = new HashSet<>(); String className; boolean isInterface; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftDifficulty.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftDifficulty.java index f8f4d7955ce2..02d4bfcda8ef 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftDifficulty.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftDifficulty.java @@ -4,6 +4,10 @@ @NullMarked public final class CraftDifficulty { + + private CraftDifficulty() { + } + public static org.bukkit.Difficulty toBukkit(net.minecraft.world.Difficulty difficulty) { return switch (difficulty) { case EASY -> org.bukkit.Difficulty.EASY; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index cfa4c67e80a5..0b061814a774 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -248,7 +248,7 @@ public Material fromLegacy(MaterialData material, boolean itemPriority) { @Override public BlockData fromLegacy(Material material, byte data) { - return CraftBlockData.fromData(CraftMagicNumbers.getBlock(material, data)); + return CraftMagicNumbers.getBlock(material, data).asBlockData(); } @Override @@ -394,8 +394,7 @@ public static boolean isLegacy(PluginDescriptionFile pdf) { public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) { // Paper start if (DISABLE_OLD_API_SUPPORT) { - // Make sure we still go through our reflection rewriting if needed - return io.papermc.paper.pluginremap.reflect.ReflectionRemapper.processClass(clazz); + return clazz; } // Paper end try { @@ -850,8 +849,8 @@ public List computeTooltipLines(final ItemSt @Override public org.bukkit.Color getSpawnEggLayerColor(final EntityType entityType, final int layer) { final net.minecraft.world.entity.EntityType nmsType = org.bukkit.craftbukkit.entity.CraftEntityType.bukkitToMinecraft(entityType); - final net.minecraft.world.item.SpawnEggItem eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); - if (eggItem != null) { + final var eggItem = net.minecraft.world.item.SpawnEggItem.byId(nmsType); + if (eggItem.isPresent()) { throw new UnsupportedOperationException(); } return null; @@ -875,6 +874,6 @@ public ItemStack deserializeItemHover(final HoverEvent.ShowItem itemHover) { return CraftItemStack.asBukkitCopy(net.minecraft.network.chat.HoverEvent.ShowItem.CODEC.codec() .parse(ops, encoded).getOrThrow(IllegalStateException::new) - .item()); + .item().create()); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftStructureTransformer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftStructureTransformer.java index 64d2e0212c8e..996dc34576a2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftStructureTransformer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftStructureTransformer.java @@ -63,18 +63,18 @@ private void destroyCopies() { private BlockTransformer[] blockTransformers; private EntityTransformer[] entityTransformers; - public CraftStructureTransformer(Cause cause, WorldGenLevel generatoraccessseed, StructureManager structuremanager, Structure structure, BoundingBox structureboundingbox, ChunkPos chunkcoordintpair) { - AsyncStructureGenerateEvent event = new AsyncStructureGenerateEvent(structuremanager.level.getMinecraftWorld().getWorld(), !Bukkit.isPrimaryThread(), cause, CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(structureboundingbox.minX(), structureboundingbox.minY(), structureboundingbox.minZ(), structureboundingbox.maxX(), structureboundingbox.maxY(), structureboundingbox.maxZ()), chunkcoordintpair.x, chunkcoordintpair.z); + public CraftStructureTransformer(Cause cause, WorldGenLevel level, StructureManager structuremanager, Structure structure, BoundingBox box, ChunkPos center) { + AsyncStructureGenerateEvent event = new AsyncStructureGenerateEvent(structuremanager.level.getMinecraftWorld().getWorld(), !Bukkit.isPrimaryThread(), cause, CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), center.x(), center.z()); Bukkit.getPluginManager().callEvent(event); this.blockTransformers = event.getBlockTransformers().values().toArray(BlockTransformer[]::new); this.entityTransformers = event.getEntityTransformers().values().toArray(EntityTransformer[]::new); - this.limitedRegion = new CraftLimitedRegion(generatoraccessseed, chunkcoordintpair); + this.limitedRegion = new CraftLimitedRegion(level, center); } - public CraftStructureTransformer(WorldGenLevel generatoraccessseed, ChunkPos chunkcoordintpair, Collection blockTransformers, Collection entityTransformers) { + public CraftStructureTransformer(WorldGenLevel level, ChunkPos center, Collection blockTransformers, Collection entityTransformers) { this.blockTransformers = blockTransformers.toArray(BlockTransformer[]::new); this.entityTransformers = entityTransformers.toArray(EntityTransformer[]::new); - this.limitedRegion = new CraftLimitedRegion(generatoraccessseed, chunkcoordintpair); + this.limitedRegion = new CraftLimitedRegion(level, center); } public boolean transformEntity(Entity entity) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedLevelAccessor.java similarity index 58% rename from paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java rename to paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedLevelAccessor.java index bb117482fe9d..280b95047b64 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/DelegatedLevelAccessor.java @@ -28,7 +28,6 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ClipBlockStateContext; import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.ColorResolver; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; @@ -59,7 +58,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.jetbrains.annotations.Nullable; -public abstract class DelegatedGeneratorAccess implements WorldGenLevel { +public abstract class DelegatedLevelAccessor implements WorldGenLevel { private WorldGenLevel delegate; @@ -82,8 +81,8 @@ public boolean ensureCanWrite(BlockPos pos) { } @Override - public void setCurrentlyGenerating(Supplier structureName) { - this.delegate.setCurrentlyGenerating(structureName); + public void setCurrentlyGenerating(Supplier currentlyGenerating) { + this.delegate.setCurrentlyGenerating(currentlyGenerating); } @Override @@ -107,13 +106,13 @@ public LevelTickAccess getBlockTicks() { } @Override - public void scheduleTick(BlockPos pos, Block block, int delay, TickPriority priority) { - this.delegate.scheduleTick(pos, block, delay, priority); + public void scheduleTick(BlockPos pos, Block type, int tickDelay, TickPriority priority) { + this.delegate.scheduleTick(pos, type, tickDelay, priority); } @Override - public void scheduleTick(BlockPos pos, Block block, int delay) { - this.delegate.scheduleTick(pos, block, delay); + public void scheduleTick(BlockPos pos, Block type, int tickDelay) { + this.delegate.scheduleTick(pos, type, tickDelay); } @Override @@ -122,13 +121,13 @@ public LevelTickAccess getFluidTicks() { } @Override - public void scheduleTick(BlockPos pos, Fluid fluid, int delay, TickPriority priority) { - this.delegate.scheduleTick(pos, fluid, delay, priority); + public void scheduleTick(BlockPos pos, Fluid type, int tickDelay, TickPriority priority) { + this.delegate.scheduleTick(pos, type, tickDelay, priority); } @Override - public void scheduleTick(BlockPos pos, Fluid fluid, int delay) { - this.delegate.scheduleTick(pos, fluid, delay); + public void scheduleTick(BlockPos pos, Fluid type, int tickDelay) { + this.delegate.scheduleTick(pos, type, tickDelay); } @Override @@ -167,58 +166,58 @@ public RandomSource getRandom() { } @Override - public void updateNeighborsAt(BlockPos pos, Block block) { - this.delegate.updateNeighborsAt(pos, block); + public void updateNeighborsAt(BlockPos pos, Block sourceBlock) { + this.delegate.updateNeighborsAt(pos, sourceBlock); } @Override - public void neighborShapeChanged(Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, @Block.UpdateFlags int flags, int recursionLeft) { - this.delegate.neighborShapeChanged(direction, pos, neighborPos, neighborState, flags, recursionLeft); + public void neighborShapeChanged(Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, @Block.UpdateFlags int updateFlags, int updateLimit) { + this.delegate.neighborShapeChanged(direction, pos, neighborPos, neighborState, updateFlags, updateLimit); } @Override - public void playSound(@Nullable final Entity entity, final BlockPos pos, final SoundEvent sound, final SoundSource source, final float volume, final float pitch) { - this.delegate.playSound(entity, pos, sound, source, volume, pitch); + public void playSound(@Nullable final Entity except, final BlockPos pos, final SoundEvent sound, final SoundSource source, final float volume, final float pitch) { + this.delegate.playSound(except, pos, sound, source, volume, pitch); } @Override - public void addParticle(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { - this.delegate.addParticle(parameters, x, y, z, velocityX, velocityY, velocityZ); + public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) { + this.delegate.addParticle(particle, x, y, z, xd, yd, zd); } @Override - public void levelEvent(Entity entity, int eventId, BlockPos pos, int data) { - this.delegate.levelEvent(entity, eventId, pos, data); + public void levelEvent(Entity source, int type, BlockPos pos, int data) { + this.delegate.levelEvent(source, type, pos, data); } @Override - public void levelEvent(int eventId, BlockPos pos, int data) { - this.delegate.levelEvent(eventId, pos, data); + public void levelEvent(int type, BlockPos pos, int data) { + this.delegate.levelEvent(type, pos, data); } @Override - public void gameEvent(Holder gameEvent, Vec3 pos, GameEvent.Context context) { - this.delegate.gameEvent(gameEvent, pos, context); + public void gameEvent(Holder gameEvent, Vec3 position, GameEvent.Context context) { + this.delegate.gameEvent(gameEvent, position, context); } @Override - public void gameEvent(Entity entity, Holder gameEvent, Vec3 pos) { - this.delegate.gameEvent(entity, gameEvent, pos); + public void gameEvent(Entity sourceEntity, Holder gameEvent, Vec3 pos) { + this.delegate.gameEvent(sourceEntity, gameEvent, pos); } @Override - public void gameEvent(Entity entity, Holder gameEvent, BlockPos pos) { - this.delegate.gameEvent(entity, gameEvent, pos); + public void gameEvent(Entity sourceEntity, Holder gameEvent, BlockPos pos) { + this.delegate.gameEvent(sourceEntity, gameEvent, pos); } @Override - public void gameEvent(Holder gameEvent, BlockPos pos, GameEvent.Context emitter) { - this.delegate.gameEvent(gameEvent, pos, emitter); + public void gameEvent(Holder gameEvent, BlockPos pos, GameEvent.Context context) { + this.delegate.gameEvent(gameEvent, pos, context); } @Override - public void gameEvent(ResourceKey gameEvent, BlockPos pos, GameEvent.Context emitter) { - this.delegate.gameEvent(gameEvent, pos, emitter); + public void gameEvent(ResourceKey gameEvent, BlockPos pos, GameEvent.Context context) { + this.delegate.gameEvent(gameEvent, pos, context); } @Override @@ -227,28 +226,28 @@ public Optional getBlockEntity(BlockPos pos, BlockEnt } @Override - public List getEntityCollisions(Entity entity, AABB box) { - return this.delegate.getEntityCollisions(entity, box); + public List getEntityCollisions(Entity source, AABB testArea) { + return this.delegate.getEntityCollisions(source, testArea); } @Override - public boolean isUnobstructed(Entity except, VoxelShape shape) { - return this.delegate.isUnobstructed(except, shape); + public boolean isUnobstructed(Entity source, VoxelShape shape) { + return this.delegate.isUnobstructed(source, shape); } @Override - public BlockPos getHeightmapPos(Heightmap.Types heightmap, BlockPos pos) { - return this.delegate.getHeightmapPos(heightmap, pos); + public BlockPos getHeightmapPos(Heightmap.Types type, BlockPos pos) { + return this.delegate.getHeightmapPos(type, pos); } @Override - public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { - return this.delegate.getChunk(chunkX, chunkZ, leastStatus, create); + public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus targetStatus, boolean loadOrGenerate) { + return this.delegate.getChunk(chunkX, chunkZ, targetStatus, loadOrGenerate); } @Override - public int getHeight(Heightmap.Types heightmap, int x, int z) { - return this.delegate.getHeight(heightmap, x, z); + public int getHeight(Heightmap.Types type, int x, int z) { + return this.delegate.getHeight(type, x, z); } @Override @@ -271,19 +270,15 @@ public Stream getBlockStatesIfLoaded(AABB box) { return this.delegate.getBlockStatesIfLoaded(box); } - @Override - public int getBlockTint(BlockPos pos, ColorResolver colorResolver) { - return this.delegate.getBlockTint(pos, colorResolver); - } @Override - public Holder getNoiseBiome(int biomeX, int biomeY, int biomeZ) { - return this.delegate.getNoiseBiome(biomeX, biomeY, biomeZ); + public Holder getNoiseBiome(int quartX, int quartY, int quartZ) { + return this.delegate.getNoiseBiome(quartX, quartY, quartZ); } @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - return this.delegate.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + public Holder getUncachedNoiseBiome(int quartX, int quartY, int quartZ) { + return this.delegate.getUncachedNoiseBiome(quartX, quartY, quartZ); } @Override @@ -342,8 +337,8 @@ public ChunkAccess getChunk(int chunkX, int chunkZ) { } @Override - public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus chunkStatus) { - return this.delegate.getChunk(chunkX, chunkZ, chunkStatus); + public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus status) { + return this.delegate.getChunk(chunkX, chunkZ, status); } @Override @@ -367,13 +362,13 @@ public int getMaxLocalRawBrightness(BlockPos pos) { } @Override - public int getMaxLocalRawBrightness(BlockPos pos, int ambientDarkness) { - return this.delegate.getMaxLocalRawBrightness(pos, ambientDarkness); + public int getMaxLocalRawBrightness(BlockPos pos, int skyDarkening) { + return this.delegate.getMaxLocalRawBrightness(pos, skyDarkening); } @Override - public boolean hasChunkAt(int x, int z) { - return this.delegate.hasChunkAt(x, z); + public boolean hasChunkAt(int blockX, int blockZ) { + return this.delegate.hasChunkAt(blockX, blockZ); } @Override @@ -382,18 +377,18 @@ public boolean hasChunkAt(BlockPos pos) { } @Override - public boolean hasChunksAt(BlockPos from, BlockPos to) { - return this.delegate.hasChunksAt(from, to); + public boolean hasChunksAt(BlockPos pos0, BlockPos pos1) { + return this.delegate.hasChunksAt(pos0, pos1); } @Override - public boolean hasChunksAt(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - return this.delegate.hasChunksAt(minX, minY, minZ, maxX, maxY, maxZ); + public boolean hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1) { + return this.delegate.hasChunksAt(x0, y0, z0, x1, y1, z1); } @Override - public boolean hasChunksAt(int minX, int minZ, int maxX, int maxZ) { - return this.delegate.hasChunksAt(minX, minZ, maxX, maxZ); + public boolean hasChunksAt(int x0, int z0, int x1, int z1) { + return this.delegate.hasChunksAt(x0, z0, x1, z1); } @Override @@ -412,14 +407,10 @@ public EnvironmentAttributeReader environmentAttributes() { } @Override - public HolderLookup holderLookup(ResourceKey> registryKey) { - return this.delegate.holderLookup(registryKey); + public HolderLookup holderLookup(ResourceKey> key) { + return this.delegate.holderLookup(key); } - @Override - public float getShade(Direction direction, boolean shade) { - return this.delegate.getShade(direction, shade); - } @Override public LevelLightEngine getLightEngine() { @@ -427,13 +418,13 @@ public LevelLightEngine getLightEngine() { } @Override - public int getBrightness(LightLayer type, BlockPos pos) { - return this.delegate.getBrightness(type, pos); + public int getBrightness(LightLayer layer, BlockPos pos) { + return this.delegate.getBrightness(layer, pos); } @Override - public int getRawBrightness(BlockPos pos, int ambientDarkness) { - return this.delegate.getRawBrightness(pos, ambientDarkness); + public int getRawBrightness(BlockPos pos, int darkening) { + return this.delegate.getRawBrightness(pos, darkening); } @Override @@ -452,68 +443,68 @@ public boolean isUnobstructed(BlockState state, BlockPos pos, CollisionContext c } @Override - public boolean isUnobstructed(Entity entity) { - return this.delegate.isUnobstructed(entity); + public boolean isUnobstructed(Entity ignore) { + return this.delegate.isUnobstructed(ignore); } @Override - public boolean noCollision(AABB collisionBox) { - return this.delegate.noCollision(collisionBox); + public boolean noCollision(AABB aabb) { + return this.delegate.noCollision(aabb); } @Override - public boolean noCollision(Entity entity) { - return this.delegate.noCollision(entity); + public boolean noCollision(Entity source) { + return this.delegate.noCollision(source); } @Override - public boolean noCollision(Entity entity, AABB collisionBox) { - return this.delegate.noCollision(entity, collisionBox); + public boolean noCollision(Entity entity, AABB aabb) { + return this.delegate.noCollision(entity, aabb); } @Override - public boolean noCollision(Entity entity, AABB collisionBox, boolean checkFluid) { - return this.delegate.noCollision(entity, collisionBox, checkFluid); + public boolean noCollision(Entity entity, AABB aabb, boolean alwaysCollideWithFluids) { + return this.delegate.noCollision(entity, aabb, alwaysCollideWithFluids); } @Override - public boolean noBlockCollision(Entity entity, AABB collisionBox) { - return this.delegate.noBlockCollision(entity, collisionBox); + public boolean noBlockCollision(Entity entity, AABB aabb) { + return this.delegate.noBlockCollision(entity, aabb); } @Override - public Iterable getCollisions(Entity entity, AABB collisionBox) { - return this.delegate.getCollisions(entity, collisionBox); + public Iterable getCollisions(Entity source, AABB box) { + return this.delegate.getCollisions(source, box); } @Override - public Iterable getBlockCollisions(Entity entity, AABB collisionBox) { - return this.delegate.getBlockCollisions(entity, collisionBox); + public Iterable getBlockCollisions(Entity source, AABB box) { + return this.delegate.getBlockCollisions(source, box); } @Override - public Iterable getBlockAndLiquidCollisions(Entity entity, AABB collisionBox) { - return this.delegate.getBlockAndLiquidCollisions(entity, collisionBox); + public Iterable getBlockAndLiquidCollisions(Entity source, AABB box) { + return this.delegate.getBlockAndLiquidCollisions(source, box); } @Override - public BlockHitResult clipIncludingBorder(ClipContext clipContext) { - return this.delegate.clipIncludingBorder(clipContext); + public BlockHitResult clipIncludingBorder(ClipContext c) { + return this.delegate.clipIncludingBorder(c); } @Override - public boolean collidesWithSuffocatingBlock(Entity entity, AABB box) { - return this.delegate.collidesWithSuffocatingBlock(entity, box); + public boolean collidesWithSuffocatingBlock(Entity source, AABB box) { + return this.delegate.collidesWithSuffocatingBlock(source, box); } @Override - public Optional findSupportingBlock(Entity entity, AABB box) { - return this.delegate.findSupportingBlock(entity, box); + public Optional findSupportingBlock(Entity source, AABB box) { + return this.delegate.findSupportingBlock(source, box); } @Override - public Optional findFreePosition(Entity entity, VoxelShape shape, Vec3 pos, double x, double y, double z) { - return this.delegate.findFreePosition(entity, shape, pos, x, y, z); + public Optional findFreePosition(Entity source, VoxelShape allowedCenters, Vec3 preferredCenter, double sizeX, double sizeY, double sizeZ) { + return this.delegate.findFreePosition(source, allowedCenters, preferredCenter, sizeX, sizeY, sizeZ); } @Override @@ -527,8 +518,8 @@ public int getDirectSignalTo(BlockPos pos) { } @Override - public int getControlInputSignal(BlockPos pos, Direction direction, boolean diodesOnly) { - return this.delegate.getControlInputSignal(pos, direction, diodesOnly); + public int getControlInputSignal(BlockPos pos, Direction direction, boolean onlyDiodes) { + return this.delegate.getControlInputSignal(pos, direction, onlyDiodes); } @Override @@ -542,8 +533,8 @@ public int getSignal(BlockPos pos, Direction direction) { } @Override - public boolean hasNeighborSignal(BlockPos pos) { - return this.delegate.hasNeighborSignal(pos); + public boolean hasNeighborSignal(BlockPos blockPos) { + return this.delegate.hasNeighborSignal(blockPos); } @Override @@ -572,33 +563,33 @@ public int getLightEmission(BlockPos pos) { } @Override - public Stream getBlockStates(AABB area) { - return this.delegate.getBlockStates(area); + public Stream getBlockStates(AABB box) { + return this.delegate.getBlockStates(box); } @Override - public BlockHitResult isBlockInLine(ClipBlockStateContext context) { - return this.delegate.isBlockInLine(context); + public BlockHitResult isBlockInLine(ClipBlockStateContext c) { + return this.delegate.isBlockInLine(c); } @Override - public BlockHitResult clip(ClipContext traverseContext, BlockPos traversePos) { - return this.delegate.clip(traverseContext, traversePos); + public BlockHitResult clip(ClipContext c, BlockPos pos) { + return this.delegate.clip(c, pos); } @Override - public BlockHitResult clip(ClipContext context) { - return this.delegate.clip(context); + public BlockHitResult clip(ClipContext c) { + return this.delegate.clip(c); } @Override - public BlockHitResult clipWithInteractionOverride(Vec3 startVec, Vec3 endVec, BlockPos pos, VoxelShape shape, BlockState state) { - return this.delegate.clipWithInteractionOverride(startVec, endVec, pos, shape, state); + public BlockHitResult clipWithInteractionOverride(Vec3 from, Vec3 to, BlockPos pos, VoxelShape blockShape, BlockState blockState) { + return this.delegate.clipWithInteractionOverride(from, to, pos, blockShape, blockState); } @Override - public double getBlockFloorHeight(VoxelShape shape, Supplier belowShapeSupplier) { - return this.delegate.getBlockFloorHeight(shape, belowShapeSupplier); + public double getBlockFloorHeight(VoxelShape blockShape, Supplier belowBlockShape) { + return this.delegate.getBlockFloorHeight(blockShape, belowBlockShape); } @Override @@ -607,18 +598,18 @@ public double getBlockFloorHeight(BlockPos pos) { } @Override - public List getEntities(Entity except, AABB area, Predicate predicate) { - return this.delegate.getEntities(except, area, predicate); + public List getEntities(Entity except, AABB bb, Predicate selector) { + return this.delegate.getEntities(except, bb, selector); } @Override - public List getEntities(EntityTypeTest entityTypeTest, AABB bounds, Predicate predicate) { - return this.delegate.getEntities(entityTypeTest, bounds, predicate); + public List getEntities(EntityTypeTest type, AABB bb, Predicate selector) { + return this.delegate.getEntities(type, bb, selector); } @Override - public List getEntitiesOfClass(Class entityClass, AABB area, Predicate filter) { - return this.delegate.getEntitiesOfClass(entityClass, area, filter); + public List getEntitiesOfClass(Class baseClass, AABB bb, Predicate selector) { + return this.delegate.getEntitiesOfClass(baseClass, bb, selector); } @Override @@ -627,33 +618,33 @@ public List players() { } @Override - public List getEntities(Entity except, AABB area) { - return this.delegate.getEntities(except, area); + public List getEntities(Entity except, AABB bb) { + return this.delegate.getEntities(except, bb); } @Override - public List getEntitiesOfClass(Class entityClass, AABB area) { - return this.delegate.getEntitiesOfClass(entityClass, area); + public List getEntitiesOfClass(Class baseClass, AABB bb) { + return this.delegate.getEntitiesOfClass(baseClass, bb); } @Override - public Player getNearestPlayer(double x, double y, double z, double maxDistance, Predicate targetPredicate) { - return this.delegate.getNearestPlayer(x, y, z, maxDistance, targetPredicate); + public Player getNearestPlayer(double x, double y, double z, double range, Predicate predicate) { + return this.delegate.getNearestPlayer(x, y, z, range, predicate); } @Override - public Player getNearestPlayer(Entity entity, double maxDistance) { - return this.delegate.getNearestPlayer(entity, maxDistance); + public Player getNearestPlayer(Entity source, double maxDist) { + return this.delegate.getNearestPlayer(source, maxDist); } @Override - public Player getNearestPlayer(double x, double y, double z, double maxDistance, boolean ignoreCreative) { - return this.delegate.getNearestPlayer(x, y, z, maxDistance, ignoreCreative); + public Player getNearestPlayer(double x, double y, double z, double maxDist, boolean filterOutCreative) { + return this.delegate.getNearestPlayer(x, y, z, maxDist, filterOutCreative); } @Override - public boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) { - return this.delegate.hasNearbyAlivePlayer(x, y, z, distance); + public boolean hasNearbyAlivePlayer(double x, double y, double z, double range) { + return this.delegate.hasNearbyAlivePlayer(x, y, z, range); } @Override @@ -662,33 +653,33 @@ public Player getPlayerByUUID(UUID uuid) { } @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, int recursionLeft) { - return this.delegate.setBlock(pos, state, flags, recursionLeft); + public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) { + return this.delegate.setBlock(pos, blockState, updateFlags, updateLimit); } @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags) { - return this.delegate.setBlock(pos, state, flags); + public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags) { + return this.delegate.setBlock(pos, blockState, updateFlags); } @Override - public boolean removeBlock(BlockPos pos, boolean isMoving) { - return this.delegate.removeBlock(pos, isMoving); + public boolean removeBlock(BlockPos pos, boolean movedByPiston) { + return this.delegate.removeBlock(pos, movedByPiston); } @Override - public boolean destroyBlock(BlockPos pos, boolean dropBlock) { - return this.delegate.destroyBlock(pos, dropBlock); + public boolean destroyBlock(BlockPos pos, boolean dropResources) { + return this.delegate.destroyBlock(pos, dropResources); } @Override - public boolean destroyBlock(BlockPos pos, boolean dropBlock, Entity entity) { - return this.delegate.destroyBlock(pos, dropBlock, entity); + public boolean destroyBlock(BlockPos pos, boolean dropResources, Entity breaker) { + return this.delegate.destroyBlock(pos, dropResources, breaker); } @Override - public boolean destroyBlock(BlockPos pos, boolean dropBlock, Entity entity, int recursionLeft) { - return this.delegate.destroyBlock(pos, dropBlock, entity, recursionLeft); + public boolean destroyBlock(BlockPos pos, boolean dropResources, Entity breaker, int updateLimit) { + return this.delegate.destroyBlock(pos, dropResources, breaker, updateLimit); } @Override @@ -722,8 +713,8 @@ public int getMaxSectionY() { } @Override - public boolean isInsideBuildHeight(int y) { - return this.delegate.isInsideBuildHeight(y); + public boolean isInsideBuildHeight(int blockY) { + return this.delegate.isInsideBuildHeight(blockY); } @Override @@ -732,18 +723,18 @@ public boolean isOutsideBuildHeight(BlockPos pos) { } @Override - public boolean isOutsideBuildHeight(int y) { - return this.delegate.isOutsideBuildHeight(y); + public boolean isOutsideBuildHeight(int blockY) { + return this.delegate.isOutsideBuildHeight(blockY); } @Override - public int getSectionIndex(int y) { - return this.delegate.getSectionIndex(y); + public int getSectionIndex(int blockY) { + return this.delegate.getSectionIndex(blockY); } @Override - public int getSectionIndexFromSectionY(int sectionIndex) { - return this.delegate.getSectionIndexFromSectionY(sectionIndex); + public int getSectionIndexFromSectionY(int sectionY) { + return this.delegate.getSectionIndexFromSectionY(sectionY); } @Override @@ -752,8 +743,8 @@ public int getSectionYFromSectionIndex(int sectionIndex) { } @Override - public boolean isStateAtPosition(BlockPos pos, Predicate state) { - return this.delegate.isStateAtPosition(pos, state); + public boolean isStateAtPosition(BlockPos pos, Predicate predicate) { + return this.delegate.isStateAtPosition(pos, predicate); } @Override @@ -779,4 +770,3 @@ public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { return this.delegate.getChunkIfLoadedImmediately(x, z); } } - diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyLevelAccessor.java similarity index 79% rename from paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java rename to paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyLevelAccessor.java index 3693c069f911..1fb4ae845640 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/DummyLevelAccessor.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.function.Predicate; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.particles.ParticleOptions; @@ -42,11 +41,11 @@ import net.minecraft.world.ticks.BlackholeTickAccess; import net.minecraft.world.ticks.LevelTickAccess; -public class DummyGeneratorAccess implements WorldGenLevel { +public class DummyLevelAccessor implements WorldGenLevel { - public static final WorldGenLevel INSTANCE = new DummyGeneratorAccess(); + public static final WorldGenLevel INSTANCE = new DummyLevelAccessor(); - protected DummyGeneratorAccess() { + protected DummyLevelAccessor() { } @Override @@ -70,7 +69,7 @@ public LevelTickAccess getBlockTicks() { } @Override - public void scheduleTick(BlockPos pos, Block block, int delay) { + public void scheduleTick(BlockPos pos, Block type, int tickDelay) { // Used by ComposterBlock } @@ -105,32 +104,32 @@ public RandomSource getRandom() { } @Override - public void playSound(Entity source, BlockPos pos, SoundEvent sound, SoundSource category, float volume, float pitch) { + public void playSound(Entity except, BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public void addParticle(ParticleOptions parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public void levelEvent(Entity entity, int eventId, BlockPos pos, int data) { + public void levelEvent(Entity source, int type, BlockPos pos, int data) { // Used by PowderSnowBlock.pickupBlock } @Override - public void gameEvent(Holder event, Vec3 emitterPos, GameEvent.Context emitter) { + public void gameEvent(Holder gameEvent, Vec3 position, GameEvent.Context context) { // Used by ComposterBlock } @Override - public List getEntities(Entity except, AABB box, Predicate predicate) { + public List getEntities(Entity except, AABB bb, Predicate selector) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public List getEntities(EntityTypeTest filter, AABB box, Predicate predicate) { + public List getEntities(EntityTypeTest type, AABB bb, Predicate selector) { throw new UnsupportedOperationException("Not supported yet."); } @@ -140,12 +139,12 @@ public List players() { } @Override - public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { + public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus targetStatus, boolean loadOrGenerate) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public int getHeight(Heightmap.Types heightmap, int x, int z) { + public int getHeight(Heightmap.Types type, int x, int z) { throw new UnsupportedOperationException("Not supported yet."); } @@ -160,7 +159,7 @@ public BiomeManager getBiomeManager() { } @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public Holder getUncachedNoiseBiome(int quartX, int quartY, int quartZ) { throw new UnsupportedOperationException("Not supported yet."); } @@ -194,11 +193,6 @@ public EnvironmentAttributeReader environmentAttributes() { return EnvironmentAttributeReader.EMPTY; } - @Override - public float getShade(Direction direction, boolean shaded) { - throw new UnsupportedOperationException("Not supported yet."); - } - @Override public LevelLightEngine getLightEngine() { throw new UnsupportedOperationException("Not supported yet."); @@ -240,36 +234,36 @@ public WorldBorder getWorldBorder() { } @Override - public boolean isStateAtPosition(BlockPos pos, Predicate state) { + public boolean isStateAtPosition(BlockPos pos, Predicate predicate) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public boolean isFluidAtPosition(BlockPos pos, Predicate state) { + public boolean isFluidAtPosition(BlockPos pos, Predicate predicate) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, int recursionLeft) { + public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) { return false; } @Override - public boolean removeBlock(BlockPos pos, boolean move) { + public boolean removeBlock(BlockPos pos, boolean movedByPiston) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int recursionLeft) { + public boolean destroyBlock(BlockPos pos, boolean dropResources, Entity breaker, int updateLimit) { return false; // SPIGOT-6515 } @Override - public void scheduleTick(BlockPos pos, Fluid fluid, int delay) {} + public void scheduleTick(BlockPos pos, Fluid type, int tickDelay) {} @Override - public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) {} + public void scheduleTick(BlockPos pos, Block type, int tickDelay, net.minecraft.world.ticks.TickPriority priority) {} @Override - public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) {} + public void scheduleTick(BlockPos pos, Fluid type, int tickDelay, net.minecraft.world.ticks.TickPriority priority) {} } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerLevelAccessor.java similarity index 71% rename from paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java rename to paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerLevelAccessor.java index c698c8438052..23b5a09cf5f4 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerGeneratorAccess.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/TransformerLevelAccessor.java @@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; -public class TransformerGeneratorAccess extends DelegatedGeneratorAccess { +public class TransformerLevelAccessor extends DelegatedLevelAccessor { private static final Logger LOGGER = LogUtils.getLogger(); @@ -51,23 +51,23 @@ public boolean addFreshEntity(Entity entity, @Nullable SpawnReason reason) { return super.addFreshEntity(entity, reason); } - public boolean setCraftBlock(BlockPos position, CraftBlockState craftBlockState, @Block.UpdateFlags int flags, int recursionLeft) { + public boolean setCraftBlock(BlockPos pos, CraftBlockState craftBlockState, @Block.UpdateFlags int updateFlags, int updateLimit) { craftBlockState = this.structureTransformer.transformCraftState(craftBlockState); // This code is based on the method 'net.minecraft.world.level.levelgen.structure.StructurePiece#placeBlock' // It ensures that any kind of block is updated correctly upon placing it BlockState snapshot = craftBlockState.getHandle(); - boolean result = super.setBlock(position, snapshot, flags, recursionLeft); - FluidState fluidState = this.getFluidState(position); + boolean result = super.setBlock(pos, snapshot, updateFlags, updateLimit); + FluidState fluidState = this.getFluidState(pos); if (!fluidState.isEmpty()) { - this.scheduleTick(position, fluidState.getType(), 0); + this.scheduleTick(pos, fluidState.getType(), 0); } if (StructurePiece.SHAPE_CHECK_BLOCKS.contains(snapshot.getBlock())) { - this.getChunk(position).markPosForPostprocessing(position); + this.getChunk(pos).markPosForPostprocessing(pos); } - BlockEntity blockEntity = this.getBlockEntity(position); + BlockEntity blockEntity = this.getBlockEntity(pos); if (blockEntity != null && craftBlockState instanceof CraftBlockEntityState craftEntityState) { try (final ProblemReporter.ScopedCollector problemReporter = new ProblemReporter.ScopedCollector( - () -> "TransformerGeneratorAccess@" + position.toShortString(), LOGGER + () -> "TransformerLevelAccessor@" + pos.toShortString(), LOGGER )) { blockEntity.loadWithComponents(TagValueInput.create( problemReporter, this.registryAccess(), craftEntityState.getSnapshotNBT() @@ -77,20 +77,20 @@ public boolean setCraftBlock(BlockPos position, CraftBlockState craftBlockState, return result; } - public boolean setCraftBlock(BlockPos pos, CraftBlockState craftBlockState, @Block.UpdateFlags int flags) { - return this.setCraftBlock(pos, craftBlockState, flags, Block.UPDATE_LIMIT); + public boolean setCraftBlock(BlockPos pos, CraftBlockState craftBlockState, @Block.UpdateFlags int updateFlags) { + return this.setCraftBlock(pos, craftBlockState, updateFlags, Block.UPDATE_LIMIT); } @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags, int recursionLeft) { + public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) { if (this.canTransformBlocks()) { - return this.setCraftBlock(pos, (CraftBlockState) CraftBlockStates.getBlockState(this, pos, state, null), flags, recursionLeft); + return this.setCraftBlock(pos, (CraftBlockState) CraftBlockStates.getBlockState(this, pos, blockState, null), updateFlags, updateLimit); } - return super.setBlock(pos, state, flags, recursionLeft); + return super.setBlock(pos, blockState, updateFlags, updateLimit); } @Override - public boolean setBlock(BlockPos pos, BlockState state, @Block.UpdateFlags int flags) { - return this.setBlock(pos, state, flags, Block.UPDATE_LIMIT); + public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags) { + return this.setBlock(pos, blockState, updateFlags, Block.UPDATE_LIMIT); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java index a454350085f2..732a2a7d504b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java @@ -84,6 +84,7 @@ public static Permission registerPermissions(Permission parent) { DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "spreadplayers", "Allows the user to teleport entities to random locations", PermissionDefault.OP, commands); DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stopsound", "Allows the user to stop a sound", PermissionDefault.OP, commands); DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "summon", "Allows the user to summon an entity", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "swing", "Allows the user to swing arms of an entity", PermissionDefault.OP, commands); DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "tag", "Allows the user to control entity tags", PermissionDefault.OP, commands); DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "team", "Allows the user to control teams", PermissionDefault.OP, commands); DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "teammsg", "Allows the user to specify the message to send to team", PermissionDefault.TRUE, commands); // defaults to all players diff --git a/paper-server/src/main/java/org/spigotmc/SpigotConfig.java b/paper-server/src/main/java/org/spigotmc/SpigotConfig.java index 97d81401484b..0e8ac5714bd8 100644 --- a/paper-server/src/main/java/org/spigotmc/SpigotConfig.java +++ b/paper-server/src/main/java/org/spigotmc/SpigotConfig.java @@ -289,12 +289,12 @@ private static void saveUserCacheOnStopOnly() { public static double movedWronglyThreshold; private static void movedWronglyThreshold() { - SpigotConfig.movedWronglyThreshold = SpigotConfig.getDouble("settings.moved-wrongly-threshold", 0.0625D); + SpigotConfig.movedWronglyThreshold = SpigotConfig.getDouble("settings.moved-wrongly-threshold", 0.0625); } public static double movedTooQuicklyMultiplier; private static void movedTooQuicklyMultiplier() { - SpigotConfig.movedTooQuicklyMultiplier = SpigotConfig.getDouble("settings.moved-too-quickly-multiplier", 10.0D); + SpigotConfig.movedTooQuicklyMultiplier = SpigotConfig.getDouble("settings.moved-too-quickly-multiplier", 10.0); } public static double maxAbsorption = 2048; diff --git a/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java b/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java index 43c6240ec285..9e63995af22b 100644 --- a/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -280,7 +280,7 @@ private void hoppers() { private void arrowDespawnRate() { this.arrowDespawnRate = this.getInt("arrow-despawn-rate", 1200); this.tridentDespawnRate = this.getInt("trident-despawn-rate", this.arrowDespawnRate); - this.log("Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Respawn Rate:" + this.tridentDespawnRate); + this.log("Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Despawn Rate:" + this.tridentDespawnRate); } public boolean zombieAggressiveTowardsVillager; diff --git a/paper-server/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/paper-server/src/main/java/org/spigotmc/TicksPerSecondCommand.java index 2756ca738b99..5eb0a3e02bcf 100644 --- a/paper-server/src/main/java/org/spigotmc/TicksPerSecondCommand.java +++ b/paper-server/src/main/java/org/spigotmc/TicksPerSecondCommand.java @@ -21,7 +21,7 @@ public class TicksPerSecondCommand extends Command { public TicksPerSecondCommand(String name) { super(name); this.description = "Gets the current ticks per second for the server"; - this.usageMessage = "/tps"; + this.usageMessage = "/tps [mem]"; this.setPermission("bukkit.command.tps"); } diff --git a/paper-server/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta b/paper-server/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta index 9d380a80550a..bcccdca454e0 100644 --- a/paper-server/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta +++ b/paper-server/src/main/resources/data/minecraft/datapacks/paper/pack.mcmeta @@ -1,7 +1,10 @@ { - "pack": { - "description": "Built-in Paper Datapack", - "min_format": 94, - "max_format": 94 - } + "pack": { + "description": "Built-in Paper Datapack", + "max_format": 101, + "min_format": [ + 101, + 1 + ] + } } diff --git a/paper-server/src/test/java/io/papermc/paper/adventure/AdventureCodecsTest.java b/paper-server/src/test/java/io/papermc/paper/adventure/AdventureCodecsTest.java index ea59a360732a..ec8053b6a7f7 100644 --- a/paper-server/src/test/java/io/papermc/paper/adventure/AdventureCodecsTest.java +++ b/paper-server/src/test/java/io/papermc/paper/adventure/AdventureCodecsTest.java @@ -39,6 +39,7 @@ import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.Identifier; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemStackTemplate; import net.minecraft.world.item.Items; import org.bukkit.support.RegistryHelper; import org.bukkit.support.environment.VanillaFeature; @@ -165,11 +166,11 @@ void testShowItemHoverEvent() { assertTrue(dataResult.result().isPresent(), () -> dataResult + " result is not present"); final net.minecraft.network.chat.HoverEvent.ShowItem nms = (net.minecraft.network.chat.HoverEvent.ShowItem) dataResult.result().orElseThrow().getFirst(); assertEquals(hoverEvent.action().toString(), nms.action().getSerializedName()); - final ItemStack item = nms.item(); - assertNotNull(item); - assertEquals(hoverEvent.value().count(), item.getCount()); - assertEquals(hoverEvent.value().item().asString(), item.getItem().toString()); - assertEquals(stack.getComponentsPatch(), item.getComponentsPatch()); + final ItemStackTemplate itemTemplate = nms.item(); + assertNotNull(itemTemplate); + assertEquals(hoverEvent.value().count(), itemTemplate.count()); + assertEquals(hoverEvent.value().item().asString(), itemTemplate.item().unwrapKey().orElseThrow().identifier().toString()); + assertEquals(stack.getComponentsPatch(), itemTemplate.components()); } @Test @@ -405,7 +406,7 @@ static List testSelectors() { static List testBlockNbts() { return List.of( - blockNBT().nbtPath("abc").localPos(1.23d, 2.0d, 3.89d).build(), + blockNBT().nbtPath("abc").localPos(1.23, 2.0, 3.89).build(), blockNBT().nbtPath("xyz").absoluteWorldPos(4, 5, 6).interpret(true).build(), blockNBT().nbtPath("eeee").relativeWorldPos(7, 83, 900) .separator(text(';')) diff --git a/paper-server/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java b/paper-server/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java index bf4365c607b0..8d4862d3aa6f 100644 --- a/paper-server/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java +++ b/paper-server/src/test/java/io/papermc/paper/block/InstrumentSoundTest.java @@ -22,7 +22,7 @@ static Stream bukkitInstruments() { @ParameterizedTest @MethodSource("bukkitInstruments") void checkInstrumentSound(final Instrument bukkit) { - final NoteBlockInstrument nms = CraftBlockData.toNMS(bukkit, NoteBlockInstrument.class); + final NoteBlockInstrument nms = CraftBlockData.toVanilla(bukkit, NoteBlockInstrument.class); assertEquals(nms.getSoundEvent(), CraftSound.bukkitToMinecraftHolder(bukkit.getSound())); } } diff --git a/paper-server/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java b/paper-server/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java index 8a83468ec2f4..a0c2fc1882bb 100644 --- a/paper-server/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java +++ b/paper-server/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java @@ -30,7 +30,6 @@ import net.kyori.adventure.util.TriState; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; -import net.minecraft.world.item.EitherHolder; import net.minecraft.world.item.Items; import net.minecraft.world.item.JukeboxSongs; import org.bukkit.Color; @@ -369,7 +368,7 @@ void testJukeboxWithEitherKey() { void testJukeboxWithEitherHolder() { final net.minecraft.world.item.ItemStack internalStack = new net.minecraft.world.item.ItemStack(Items.STONE); internalStack.set(DataComponents.JUKEBOX_PLAYABLE, new net.minecraft.world.item.JukeboxPlayable( - new EitherHolder<>(RegistryHelper.registryAccess().lookupOrThrow(Registries.JUKEBOX_SONG).getOrThrow(JukeboxSongs.FIVE)) + RegistryHelper.registryAccess().lookupOrThrow(Registries.JUKEBOX_SONG).getOrThrow(JukeboxSongs.FIVE) )); final ItemStack apiStack = CraftItemStack.asBukkitCopy(internalStack); diff --git a/paper-server/src/test/java/org/bukkit/BlockDataConversionTest.java b/paper-server/src/test/java/org/bukkit/BlockDataConversionTest.java index d6a1e4c42254..541ee0d98210 100644 --- a/paper-server/src/test/java/org/bukkit/BlockDataConversionTest.java +++ b/paper-server/src/test/java/org/bukkit/BlockDataConversionTest.java @@ -1,16 +1,16 @@ package org.bukkit; -import static org.junit.jupiter.api.Assertions.*; import java.util.stream.Stream; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.support.environment.AllFeatures; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * This test class ensures that all Blocks (as registered in BuiltInRegistries.BLOCK) * can be converted into their CraftBlockData equivalent. @@ -26,6 +26,6 @@ public static Stream data() { @MethodSource("data") public void testNotNull(BlockState state) { assertNotNull(state); - assertNotNull(CraftBlockData.fromData(state)); + assertNotNull(state.asBlockData()); } } diff --git a/paper-server/src/test/java/org/bukkit/BlockDataTest.java b/paper-server/src/test/java/org/bukkit/BlockDataTest.java index 9168a173577d..cd910ad0a4f0 100644 --- a/paper-server/src/test/java/org/bukkit/BlockDataTest.java +++ b/paper-server/src/test/java/org/bukkit/BlockDataTest.java @@ -1,9 +1,5 @@ package org.bukkit; -import static org.bukkit.support.MatcherAssert.*; -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.*; - import net.minecraft.core.Direction; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.CakeBlock; @@ -17,56 +13,66 @@ import org.bukkit.support.environment.VanillaFeature; import org.junit.jupiter.api.Test; +import static org.bukkit.support.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + @VanillaFeature public class BlockDataTest { @Test public void testParsing() { - BlockData cakeTest = CraftBlockData.fromData(Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3)); + BlockData cakeTest = Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3).asBlockData(); - BlockData materialString = CraftBlockData.newData(BlockType.CAKE, "[bites=3]"); + BlockData materialString = CraftBlockData.fromString(BlockType.CAKE, "[bites=3]"); assertThat(materialString, is(cakeTest)); - BlockData combined = CraftBlockData.newData(null, "cake[bites=3]"); + BlockData combined = CraftBlockData.fromString(null, "cake[bites=3]"); assertThat(combined, is(cakeTest)); - BlockData combinedMinecraft = CraftBlockData.newData(null, "minecraft:cake[bites=3]"); + BlockData combinedMinecraft = CraftBlockData.fromString(null, "minecraft:cake[bites=3]"); assertThat(combinedMinecraft, is(cakeTest)); - BlockData inverted = CraftBlockData.newData(null, cakeTest.getAsString()); + BlockData inverted = CraftBlockData.fromString(null, cakeTest.getAsString()); assertThat(inverted, is(cakeTest)); } @Test public void testBadMaterial() { - assertThrows(IllegalArgumentException.class, () -> CraftBlockData.newData(null, "invalid")); + assertThrows(IllegalArgumentException.class, () -> CraftBlockData.fromString(null, "invalid")); } @Test public void testBadSyntax() { - assertThrows(IllegalArgumentException.class, () -> CraftBlockData.newData(null, "minecraft:cake[bites=3")); + assertThrows(IllegalArgumentException.class, () -> CraftBlockData.fromString(null, "minecraft:cake[bites=3")); } @Test public void testDoubleMaterial() { - assertThrows(IllegalArgumentException.class, () -> CraftBlockData.newData(BlockType.CAKE, "minecraft:cake[bites=3]")); + assertThrows(IllegalArgumentException.class, () -> CraftBlockData.fromString(BlockType.CAKE, "minecraft:cake[bites=3]")); } @Test public void testMistake() { - BlockData cakeTest = CraftBlockData.fromData(Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3)); + BlockData cakeTest = Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3).asBlockData(); - assertThrows(IllegalArgumentException.class, () -> CraftBlockData.newData(BlockType.CAKE, cakeTest.toString())); + assertThrows(IllegalArgumentException.class, () -> CraftBlockData.fromString(BlockType.CAKE, cakeTest.toString())); } @Test public void testItemParse() { - assertThrows(IllegalArgumentException.class, () -> CraftBlockData.newData(null, "minecraft:diamond_axe")); + assertThrows(IllegalArgumentException.class, () -> CraftBlockData.fromString(null, "minecraft:diamond_axe")); } @Test public void testClone() { - Cake cakeTest = (Cake) CraftBlockData.fromData(Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3)); + Cake cakeTest = (Cake) Blocks.CAKE.defaultBlockState().setValue(CakeBlock.BITES, 3).asBlockData(); Cake clone = (Cake) cakeTest.clone(); assertNotSame(cakeTest, clone, "Clone did not return new object"); @@ -78,9 +84,9 @@ public void testClone() { @Test public void testMerge() { - Chest trueTarget = (Chest) CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]"); - Chest falseTarget = (Chest) CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=false]"); - Chest waterlogged = (Chest) CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"); + Chest trueTarget = (Chest) CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]"); + Chest falseTarget = (Chest) CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=false]"); + Chest waterlogged = (Chest) CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"); BlockData candidate; @@ -95,9 +101,9 @@ public void testMerge() { @Test public void testMergeAny() { - Chest trueTarget = (Chest) CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]"); - Chest falseTarget = (Chest) CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=false]"); - Chest any = (Chest) CraftBlockData.newData(null, "minecraft:chest"); + Chest trueTarget = (Chest) CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]"); + Chest falseTarget = (Chest) CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=false]"); + Chest any = (Chest) CraftBlockData.fromString(null, "minecraft:chest"); BlockData candidate; @@ -112,16 +118,16 @@ public void testMergeAny() { @Test public void testCannotMerge1() { - Chest one = (Chest) CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]"); - Chest two = (Chest) CraftBlockData.fromData(Blocks.CHEST.defaultBlockState()); + Chest one = (Chest) CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]"); + Chest two = (Chest) Blocks.CHEST.defaultBlockState().asBlockData(); assertThrows(IllegalArgumentException.class, () -> one.merge(two)); } @Test public void testCannotMerge2() { - Chest one = (Chest) CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"); - Chest two = (Chest) CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"); + Chest one = (Chest) CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"); + Chest two = (Chest) CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"); one.merge(two); @@ -131,22 +137,22 @@ public void testCannotMerge2() { @Test public void testCannotMerge3() { - Chest one = (Chest) CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"); - Chest two = (Chest) CraftBlockData.newData(null, "minecraft:trapped_chest[waterlogged=true]"); + Chest one = (Chest) CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"); + Chest two = (Chest) CraftBlockData.fromString(null, "minecraft:trapped_chest[waterlogged=true]"); assertThrows(IllegalArgumentException.class, () -> one.merge(two)); } @Test public void testMatch() { - assertTrue(CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"))); - assertFalse(CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=false]").matches(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"))); - assertTrue(CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.newData(null, "minecraft:chest"))); - assertFalse(CraftBlockData.newData(null, "minecraft:trapped_chest[facing=east,waterlogged=false]").matches(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"))); - assertTrue(CraftBlockData.newData(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true,facing=east]"))); + assertTrue(CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"))); + assertFalse(CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=false]").matches(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"))); + assertTrue(CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.fromString(null, "minecraft:chest"))); + assertFalse(CraftBlockData.fromString(null, "minecraft:trapped_chest[facing=east,waterlogged=false]").matches(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"))); + assertTrue(CraftBlockData.fromString(null, "minecraft:chest[facing=east,waterlogged=true]").matches(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true,facing=east]"))); - Chest one = (Chest) CraftBlockData.fromData(Blocks.CHEST.defaultBlockState().setValue(ChestBlock.FACING, Direction.EAST)); - Chest two = (Chest) CraftBlockData.newData(null, "minecraft:chest[waterlogged=false]"); + Chest one = (Chest) Blocks.CHEST.defaultBlockState().setValue(ChestBlock.FACING, Direction.EAST).asBlockData(); + Chest two = (Chest) CraftBlockData.fromString(null, "minecraft:chest[waterlogged=false]"); assertTrue(one.matches(two)); assertFalse(two.matches(one)); @@ -155,7 +161,7 @@ public void testMatch() { @Test public void testGetAsString() { String dataString = "minecraft:chest[facing=east,waterlogged=true]"; - BlockData data = CraftBlockData.newData(null, dataString); + BlockData data = CraftBlockData.fromString(null, dataString); assertThat(data.getAsString(true), is(dataString)); assertThat(data.getAsString(false), is("minecraft:chest[facing=east,type=single,waterlogged=true]")); @@ -163,7 +169,7 @@ public void testGetAsString() { @Test public void testGetAsString2() { - Chest data = (Chest) CraftBlockData.fromData(Blocks.CHEST.defaultBlockState().setValue(ChestBlock.FACING, Direction.EAST)); + Chest data = (Chest) Blocks.CHEST.defaultBlockState().setValue(ChestBlock.FACING, Direction.EAST).asBlockData(); assertThat(data.getAsString(true), is("minecraft:chest[facing=east,type=single,waterlogged=false]")); assertThat(data.getAsString(false), is("minecraft:chest[facing=east,type=single,waterlogged=false]")); diff --git a/paper-server/src/test/java/org/bukkit/InstrumentTest.java b/paper-server/src/test/java/org/bukkit/InstrumentTest.java index 0363b615f3a7..35ec6465708e 100644 --- a/paper-server/src/test/java/org/bukkit/InstrumentTest.java +++ b/paper-server/src/test/java/org/bukkit/InstrumentTest.java @@ -7,13 +7,12 @@ import static org.hamcrest.CoreMatchers.is; @Normal -public class InstrumentTest { // Paper - moved to internals as this test now access the sound registry. +@Deprecated +public class InstrumentTest { @Test public void getByType() { for (Instrument instrument : Instrument.values()) { - // Paper - byte magic values are still used - assertThat(Instrument.getByType(instrument.getType()), is(instrument)); } } diff --git a/paper-server/src/test/java/org/bukkit/ParticleTest.java b/paper-server/src/test/java/org/bukkit/ParticleTest.java index 414586df882d..471147bde16a 100644 --- a/paper-server/src/test/java/org/bukkit/ParticleTest.java +++ b/paper-server/src/test/java/org/bukkit/ParticleTest.java @@ -2,7 +2,7 @@ import com.mojang.serialization.DataResult; import java.util.Optional; -import java.util.stream.Stream; +import java.util.Set; import net.minecraft.core.particles.BlockParticleOption; import net.minecraft.core.particles.ColorParticleOption; import net.minecraft.core.particles.DustColorTransitionOptions; @@ -24,7 +24,6 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftParticle; import org.bukkit.craftbukkit.CraftRegistry; -import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.inventory.ItemStack; @@ -32,7 +31,6 @@ import org.joml.Vector3f; import org.joml.Vector4f; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; @@ -46,8 +44,8 @@ @VanillaFeature public class ParticleTest { - public static Stream data() { - return CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE).keySet().stream().map(Arguments::of); + public static Set data() { + return CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE).keySet(); } @ParameterizedTest @@ -160,10 +158,11 @@ private void testDustOption(Particle bukkit, net.min } private void testItemStack(Particle bukkit, net.minecraft.core.particles.ParticleType minecraft) { - ItemStack itemStack = new ItemStack(Material.STONE); + ItemStack itemStack = ItemStack.of(Material.STONE); ItemParticleOption param = this.createAndTest(bukkit, minecraft, itemStack, ItemParticleOption.class); - assertEquals(itemStack, CraftItemStack.asBukkitCopy(param.getItem()), String.format(""" + // TODO - snapshot - uses template + assertEquals(itemStack, CraftItemStack.asBukkitCopy(param.getItem().create()), String.format(""" ItemStack for particle %s do not match. Did something change in the implementation or minecraft? """, bukkit.getKey())); @@ -173,7 +172,7 @@ private void testBlockData(Particle bukkit, net.mine BlockData blockData = Bukkit.createBlockData(Material.STONE); BlockParticleOption param = this.createAndTest(bukkit, minecraft, blockData, BlockParticleOption.class); - assertEquals(blockData, CraftBlockData.fromData(param.getState()), String.format(""" + assertEquals(blockData, param.getState().asBlockData(), String.format(""" Block data for particle %s do not match. Did something change in the implementation or minecraft? """, bukkit.getKey())); diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/generator/ChunkDataTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/generator/ChunkDataTest.java index d484d1de01bc..8f5eb2df8989 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/generator/ChunkDataTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/generator/ChunkDataTest.java @@ -1,6 +1,8 @@ package org.bukkit.craftbukkit.generator; import static org.junit.jupiter.api.Assertions.*; + +import net.minecraft.world.level.chunk.PalettedContainerFactory; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.support.RegistryHelper; @@ -34,23 +36,30 @@ private void testSetRegion(OldCraftChunkData data, int minx, int miny, int minz, } } + private static PalettedContainerFactory palettedContainerFactory() { + final class Holder { + public static final PalettedContainerFactory FACTORY = PalettedContainerFactory.create(RegistryHelper.registryAccess()); + } + return Holder.FACTORY; + } + @Test public void testMinHeight() { - OldCraftChunkData data = new OldCraftChunkData(-128, 128, RegistryHelper.context().palettedContainerFactory().get()); + OldCraftChunkData data = new OldCraftChunkData(-128, 128, palettedContainerFactory()); assertTrue(this.testSetBlock(data, 0, -256, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.AIR), "Could not set block below min height"); assertTrue(this.testSetBlock(data, 0, -64, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.RED_WOOL), "Could set block above min height"); } @Test public void testMaxHeight() { - OldCraftChunkData data = new OldCraftChunkData(0, 128, RegistryHelper.context().palettedContainerFactory().get()); + OldCraftChunkData data = new OldCraftChunkData(0, 128, palettedContainerFactory()); assertTrue(this.testSetBlock(data, 0, 128, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.AIR), "Could not set block above max height"); assertTrue(this.testSetBlock(data, 0, 127, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.RED_WOOL), "Could set block below max height"); } @Test public void testBoundsCheckingSingle() { - OldCraftChunkData data = new OldCraftChunkData(0, 256, RegistryHelper.context().palettedContainerFactory().get()); + OldCraftChunkData data = new OldCraftChunkData(0, 256, palettedContainerFactory()); assertTrue(this.testSetBlock(data, 0, 0, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.RED_WOOL), "Can set block inside chunk bounds"); assertTrue(this.testSetBlock(data, 15, 255, 15, ChunkDataTest.RED_WOOL, ChunkDataTest.RED_WOOL), "Can set block inside chunk bounds"); assertTrue(this.testSetBlock(data, -1, 0, 0, ChunkDataTest.RED_WOOL, ChunkDataTest.AIR), "Can no set block outside chunk bounds"); @@ -63,7 +72,7 @@ public void testBoundsCheckingSingle() { @Test public void testSetRegion() { - OldCraftChunkData data = new OldCraftChunkData(0, 256, RegistryHelper.context().palettedContainerFactory().get()); + OldCraftChunkData data = new OldCraftChunkData(0, 256, palettedContainerFactory()); this.testSetRegion(data, -100, 0, -100, 0, 256, 0, ChunkDataTest.RED_WOOL); // exclusively outside this.testSetRegion(data, 16, 256, 16, 0, 0, 0, ChunkDataTest.RED_WOOL); // minimum >= maximum this.testSetRegion(data, 0, 0, 0, 0, 0, 0, ChunkDataTest.RED_WOOL); // minimum == maximum diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java index cd783d3de3e4..f375aea89cf9 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java @@ -46,7 +46,6 @@ import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.inventory.meta.SpawnEggMeta; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; @@ -430,8 +429,8 @@ public void testAttributeModifiers() { @Test public void testBlockData() { BlockDataMeta itemMeta = (BlockDataMeta) Bukkit.getItemFactory().getItemMeta(Material.CHEST); - itemMeta.setBlockData(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]")); - assertThat(itemMeta.getBlockData(Material.CHEST), is(CraftBlockData.newData(null, "minecraft:chest[waterlogged=true]"))); + itemMeta.setBlockData(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]")); + assertThat(itemMeta.getBlockData(Material.CHEST), is(CraftBlockData.fromString(null, "minecraft:chest[waterlogged=true]"))); } @Test diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java index c6e5e2506b46..62f41aa7e711 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java @@ -156,6 +156,8 @@ public class LegacyTest { // 1.21.11 Material.COPPER_NAUTILUS_ARMOR, Material.COPPER_SPEAR, Material.DIAMOND_NAUTILUS_ARMOR, Material.DIAMOND_SPEAR, Material.GOLDEN_NAUTILUS_ARMOR, Material.GOLDEN_SPEAR, Material.IRON_NAUTILUS_ARMOR, Material.IRON_SPEAR, Material.NAUTILUS_SPAWN_EGG, Material.NETHERITE_NAUTILUS_ARMOR, Material.NETHERITE_SPEAR, Material.STONE_SPEAR, Material.WOODEN_SPEAR, Material.ZOMBIE_NAUTILUS_SPAWN_EGG, Material.CAMEL_HUSK_SPAWN_EGG, Material.PARCHED_SPAWN_EGG, Material.NETHERITE_HORSE_ARMOR, + // 26.1 + Material.GOLDEN_DANDELION, Material.POTTED_GOLDEN_DANDELION, // Material.LEGACY_AIR, Material.LEGACY_DEAD_BUSH, Material.LEGACY_BURNING_FURNACE, Material.LEGACY_WALL_SIGN, Material.LEGACY_REDSTONE_TORCH_OFF, Material.LEGACY_SKULL, Material.LEGACY_REDSTONE_COMPARATOR_ON, Material.LEGACY_WALL_BANNER, Material.LEGACY_MONSTER_EGG)); diff --git a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java index 2718c82e0b6b..90d6a0d542d2 100644 --- a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java +++ b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java @@ -56,7 +56,8 @@ public static void populateIgnored() { DataComponents.BLOCK_ENTITY_DATA, DataComponents.BUCKET_ENTITY_DATA, DataComponents.LOCK, - DataComponents.CREATIVE_SLOT_LOCK + DataComponents.CREATIVE_SLOT_LOCK, + DataComponents.ADDITIONAL_TRADE_COST )); } diff --git a/paper-server/src/test/java/org/bukkit/support/DummyServerHelper.java b/paper-server/src/test/java/org/bukkit/support/DummyServerHelper.java index c6e49a553c30..5811a3bbde12 100644 --- a/paper-server/src/test/java/org/bukkit/support/DummyServerHelper.java +++ b/paper-server/src/test/java/org/bukkit/support/DummyServerHelper.java @@ -40,7 +40,7 @@ public static Server setup() { when(instance.getUnsafe()).then(mock -> CraftMagicNumbers.INSTANCE); - when(instance.createBlockData(any(Material.class))).then(mock -> CraftBlockData.newData(((Material) mock.getArgument(0)).asBlockType(), null)); + when(instance.createBlockData(any(Material.class))).then(mock -> CraftBlockData.fromString(((Material) mock.getArgument(0)).asBlockType(), null)); when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0), RegistryHelper.context().datapack().fullRegistries().getLootTable(ResourceKey.create(Registries.LOOT_TABLE, CraftNamespacedKey.toMinecraft(mock.getArgument(0)))))); diff --git a/paper-server/src/test/java/org/bukkit/support/RegistryHelper.java b/paper-server/src/test/java/org/bukkit/support/RegistryHelper.java index 8bf9b94d0bb6..007c49e0de7b 100644 --- a/paper-server/src/test/java/org/bukkit/support/RegistryHelper.java +++ b/paper-server/src/test/java/org/bukkit/support/RegistryHelper.java @@ -2,7 +2,6 @@ import java.util.List; import java.util.Locale; -import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Stream; import net.minecraft.SharedConstants; @@ -29,7 +28,6 @@ import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.level.DataPackConfig; import net.minecraft.world.level.WorldDataConfiguration; -import net.minecraft.world.level.chunk.PalettedContainerFactory; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; @@ -56,8 +54,7 @@ public static SetupContext context() { public record SetupContext( ReloadableServerResources datapack, - RegistryAccess registries, - Supplier palettedContainerFactory + RegistryAccess registries ) { } @@ -78,11 +75,11 @@ public static PackedRegistries createRegistries(ResourceManager resourceManager) List> pendingTags = TagLoader.loadTagsForExistingRegistries(resourceManager, layers.getLayer(RegistryLayer.STATIC)); List> lookupsWithPendingTags = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLDGEN), pendingTags); - RegistryAccess.Frozen worldGenRegistries = RegistryDataLoader.load(resourceManager, lookupsWithPendingTags, RegistryDataLoader.WORLDGEN_REGISTRIES); + RegistryAccess.Frozen worldGenRegistries = RegistryDataLoader.load(resourceManager, lookupsWithPendingTags, RegistryDataLoader.WORLDGEN_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.WORLDGEN, worldGenRegistries); List> staticAndWorldgenLookups = Stream.concat(lookupsWithPendingTags.stream(), worldGenRegistries.listRegistries()).toList(); - RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES); + RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensionRegistries); // load registry here to ensure bukkit object registry are correctly delayed if needed try { @@ -104,13 +101,12 @@ public static void setup(FeatureFlagSet enabledFeatures) { // Register vanilla packs ReloadableServerResources datapack = ReloadableServerResources.loadResources(resourceManager, registries.layers(), registries.pendingTags(), enabledFeatures, Commands.CommandSelection.DEDICATED, LevelBasedPermissionSet.ALL_PERMISSIONS, Util.backgroundExecutor(), Runnable::run).join(); // Bind tags - datapack.updateStaticRegistryTags(); + datapack.updateComponentsAndStaticRegistryTags(); RegistryAccess registryAccess = registries.access(); setupContext = new SetupContext( datapack, - registryAccess, - () -> PalettedContainerFactory.create(registryAccess) + registryAccess ); } @@ -138,7 +134,7 @@ private static MultiPackResourceManager createResourceManager(FeatureFlagSet ena private static final Pattern ILLEGAL_FIELD_CHARACTERS = Pattern.compile("[.-/]"); - public static String formatKeyAsField(String path) { + private static String formatKeyAsField(String path) { return ILLEGAL_FIELD_CHARACTERS.matcher(path.toUpperCase(Locale.ENGLISH)).replaceAll("_"); } } diff --git a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java index 00b949fc0982..0f849c2ffc66 100644 --- a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java @@ -13,12 +13,16 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.entity.animal.feline.CatVariant; +import net.minecraft.world.entity.animal.chicken.ChickenSoundVariant; import net.minecraft.world.entity.animal.chicken.ChickenVariant; +import net.minecraft.world.entity.animal.cow.CowSoundVariant; import net.minecraft.world.entity.animal.cow.CowVariant; -import net.minecraft.world.entity.animal.pig.PigVariant; -import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.feline.CatSoundVariant; +import net.minecraft.world.entity.animal.feline.CatVariant; import net.minecraft.world.entity.animal.frog.FrogVariant; +import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.pig.PigSoundVariant; +import net.minecraft.world.entity.animal.pig.PigVariant; import net.minecraft.world.entity.animal.wolf.WolfSoundVariant; import net.minecraft.world.entity.animal.wolf.WolfVariant; import net.minecraft.world.entity.decoration.painting.PaintingVariant; @@ -139,13 +143,17 @@ public Object[] get() { register(Registries.BLOCK, BlockType.class, CraftBlockType.class, net.minecraft.world.level.block.Block.class); register(Registries.FROG_VARIANT, Frog.Variant.class, CraftFrog.CraftVariant.class, FrogVariant.class); register(Registries.CAT_VARIANT, Cat.Type.class, CraftCat.CraftType.class, CatVariant.class); + register(Registries.CAT_SOUND_VARIANT, Cat.SoundVariant.class, CraftCat.CraftSoundVariant.class, CatSoundVariant.class); register(Registries.MAP_DECORATION_TYPE, MapCursor.Type.class, CraftMapCursor.CraftType.class, MapDecorationType.class); register(Registries.BANNER_PATTERN, PatternType.class, CraftPatternType.class, BannerPattern.class); register(Registries.MENU, MenuType.class, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); register(Registries.DATA_COMPONENT_TYPE, io.papermc.paper.datacomponent.DataComponentType.class, DataComponentTypes.class, io.papermc.paper.datacomponent.PaperDataComponentType.class, net.minecraft.core.component.DataComponentType.class); register(Registries.CHICKEN_VARIANT, Chicken.Variant.class, CraftChicken.CraftVariant.class, ChickenVariant.class); + register(Registries.CHICKEN_SOUND_VARIANT, Chicken.SoundVariant.class, CraftChicken.CraftSoundVariant.class, ChickenSoundVariant.class); register(Registries.COW_VARIANT, Cow.Variant.class, CraftCow.CraftVariant.class, CowVariant.class); + register(Registries.COW_SOUND_VARIANT, Cow.SoundVariant.class, CraftCow.CraftSoundVariant.class, CowSoundVariant.class); register(Registries.PIG_VARIANT, Pig.Variant.class, CraftPig.CraftVariant.class, PigVariant.class); + register(Registries.PIG_SOUND_VARIANT, Pig.SoundVariant.class, CraftPig.CraftSoundVariant.class, PigSoundVariant.class); register(Registries.ZOMBIE_NAUTILUS_VARIANT, ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant.class, ZombieNautilusVariant.class); register(Registries.DIALOG, Dialog.class, PaperDialog.class, net.minecraft.server.dialog.Dialog.class); register(Registries.GAME_RULE, GameRule.class, GameRules.class, CraftGameRule.class, net.minecraft.world.level.gamerules.GameRule.class);