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 a6b71ce601..790eea04e1 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 @@ -79,7 +79,7 @@ + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess convertable; + public final UUID uuid; -+ + + public LevelChunk getChunkIfLoaded(int x, int z) { + return this.chunkSource.getChunk(x, z, false); + } @@ -103,7 +103,7 @@ + ChunkGenerator chunkgenerator = worlddimension.generator(); + // CraftBukkit start + this.serverLevelData.setWorld(this); - ++ + if (biomeProvider != null) { + BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME)); + if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) { @@ -230,7 +230,7 @@ if (flag1) { this.resetEmptyTime(); -@@ -353,12 +413,14 @@ +@@ -353,12 +413,15 @@ if (flag1 || this.emptyTime++ < 300) { gameprofilerfiller.push("entities"); @@ -241,11 +241,12 @@ gameprofilerfiller.pop(); } ++ org.spigotmc.ActivationRange.activateEntities(this); // Spigot + this.timings.entityTick.startTiming(); // Spigot this.entityTickList.forEach((entity) -> { if (!entity.isRemoved()) { if (!tickratemanager.isEntityFrozen(entity)) { -@@ -383,6 +445,8 @@ +@@ -383,6 +446,8 @@ } } }); @@ -254,7 +255,7 @@ gameprofilerfiller.pop(); this.tickBlockEntities(); } -@@ -429,7 +493,7 @@ +@@ -429,7 +494,7 @@ private void wakeUpAllPlayers() { this.sleepStatus.removeAllSleepers(); @@ -263,7 +264,7 @@ entityplayer.stopSleepInBed(false, false); }); } -@@ -456,7 +520,7 @@ +@@ -456,7 +521,7 @@ entityhorseskeleton.setTrap(true); entityhorseskeleton.setAge(0); entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); @@ -272,7 +273,7 @@ } } -@@ -465,7 +529,7 @@ +@@ -465,7 +530,7 @@ if (entitylightning != null) { entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition)); entitylightning.setVisualOnly(flag1); @@ -281,7 +282,7 @@ } } } -@@ -521,7 +585,7 @@ +@@ -521,7 +586,7 @@ Biome biomebase = (Biome) this.getBiome(blockposition1).value(); if (biomebase.shouldFreeze(this, blockposition2)) { @@ -290,7 +291,7 @@ } if (this.isRaining()) { -@@ -537,10 +601,10 @@ +@@ -537,10 +602,10 @@ BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1); Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1); @@ -303,7 +304,7 @@ } } -@@ -701,33 +765,67 @@ +@@ -701,33 +766,67 @@ this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F); } @@ -379,15 +380,22 @@ } public void resetEmptyTime() { -@@ -754,6 +852,7 @@ +@@ -754,6 +853,14 @@ } public void tickNonPassenger(Entity entity) { ++ // Spigot start ++ if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { ++ entity.tickCount++; ++ entity.inactiveTick(); ++ return; ++ } ++ // Spigot end + entity.tickTimer.startTiming(); // Spigot entity.setOldPosAndRot(); ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -763,6 +862,7 @@ +@@ -763,6 +870,7 @@ }); gameprofilerfiller.incrementCounter("tickNonPassenger"); entity.tick(); @@ -395,7 +403,7 @@ gameprofilerfiller.pop(); Iterator iterator = entity.getPassengers().iterator(); -@@ -771,6 +871,7 @@ +@@ -771,6 +879,7 @@ this.tickPassenger(entity, entity1); } @@ -403,7 +411,7 @@ } -@@ -786,6 +887,7 @@ +@@ -786,6 +895,7 @@ }); gameprofilerfiller.incrementCounter("tickPassenger"); passenger.rideTick(); @@ -411,7 +419,7 @@ gameprofilerfiller.pop(); Iterator iterator = passenger.getPassengers().iterator(); -@@ -810,6 +912,7 @@ +@@ -810,6 +920,7 @@ ServerChunkCache chunkproviderserver = this.getChunkSource(); if (!savingDisabled) { @@ -419,7 +427,7 @@ if (progressListener != null) { progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); } -@@ -827,11 +930,19 @@ +@@ -827,11 +938,19 @@ } } @@ -440,7 +448,7 @@ } DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage(); -@@ -903,18 +1014,40 @@ +@@ -903,18 +1022,40 @@ @Override public boolean addFreshEntity(Entity entity) { @@ -484,7 +492,7 @@ } } -@@ -939,24 +1072,38 @@ +@@ -939,24 +1080,38 @@ this.entityManager.addNewEntity(player); } @@ -527,7 +535,7 @@ return true; } } -@@ -967,13 +1114,35 @@ +@@ -967,13 +1122,35 @@ } public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) { @@ -564,7 +572,7 @@ while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -982,6 +1151,12 @@ +@@ -982,6 +1159,12 @@ double d1 = (double) pos.getY() - entityplayer.getY(); double d2 = (double) pos.getZ() - entityplayer.getZ(); @@ -577,7 +585,7 @@ if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress)); } -@@ -1060,7 +1235,18 @@ +@@ -1060,7 +1243,18 @@ Iterator iterator = this.navigatingMobs.iterator(); while (iterator.hasNext()) { @@ -597,7 +605,7 @@ PathNavigation navigationabstract = entityinsentient.getNavigation(); if (navigationabstract.shouldRecomputePath(pos)) { -@@ -1126,9 +1312,15 @@ +@@ -1126,9 +1320,15 @@ @Override public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder soundEvent) { @@ -614,7 +622,7 @@ case NONE: explosion_effect = Explosion.BlockInteraction.KEEP; break; -@@ -1144,16 +1336,26 @@ +@@ -1144,16 +1344,26 @@ case TRIGGER: explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK; break; @@ -644,7 +652,7 @@ Iterator iterator = this.players.iterator(); while (iterator.hasNext()) { -@@ -1162,10 +1364,11 @@ +@@ -1162,10 +1372,11 @@ if (entityplayer.distanceToSqr(vec3d) < 4096.0D) { Optional optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer)); @@ -657,7 +665,7 @@ } private Explosion.BlockInteraction getDestroyType(GameRules.Key decayRule) { -@@ -1226,17 +1429,24 @@ +@@ -1226,17 +1437,24 @@ } public int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) { @@ -685,7 +693,7 @@ ++j; } } -@@ -1292,7 +1502,7 @@ +@@ -1292,7 +1510,7 @@ @Nullable public BlockPos findNearestMapStructure(TagKey structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) { @@ -694,7 +702,7 @@ return null; } else { Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); -@@ -1334,11 +1544,22 @@ +@@ -1334,11 +1552,22 @@ @Nullable @Override public MapItemSavedData getMapData(MapId id) { @@ -718,7 +726,7 @@ this.getServer().overworld().getDataStorage().set(id.key(), state); } -@@ -1649,6 +1870,11 @@ +@@ -1649,6 +1878,11 @@ @Override public void blockUpdated(BlockPos pos, Block block) { if (!this.isDebug()) { @@ -730,7 +738,7 @@ this.updateNeighborsAt(pos, block); } -@@ -1668,12 +1894,12 @@ +@@ -1668,12 +1902,12 @@ } public boolean isFlat() { @@ -745,7 +753,7 @@ } @Nullable -@@ -1696,7 +1922,7 @@ +@@ -1696,7 +1930,7 @@ private static String getTypeCount(Iterable items, Function classifier) { try { Object2IntOpenHashMap object2intopenhashmap = new Object2IntOpenHashMap(); @@ -754,7 +762,7 @@ while (iterator.hasNext()) { T t0 = iterator.next(); -@@ -1705,7 +1931,7 @@ +@@ -1705,7 +1939,7 @@ object2intopenhashmap.addTo(s, 1); } @@ -763,7 +771,7 @@ String s1 = (String) entry.getKey(); return s1 + ":" + entry.getIntValue(); -@@ -1717,6 +1943,7 @@ +@@ -1717,6 +1951,7 @@ @Override public LevelEntityGetter getEntities() { @@ -771,7 +779,7 @@ return this.entityManager.getEntityGetter(); } -@@ -1836,6 +2063,7 @@ +@@ -1836,6 +2071,7 @@ } public void onTrackingStart(Entity entity) { @@ -779,7 +787,7 @@ ServerLevel.this.getChunkSource().addEntity(entity); if (entity instanceof ServerPlayer entityplayer) { ServerLevel.this.players.add(entityplayer); -@@ -1864,9 +2092,12 @@ +@@ -1864,9 +2100,12 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -792,7 +800,7 @@ ServerLevel.this.getChunkSource().removeEntity(entity); if (entity instanceof ServerPlayer entityplayer) { ServerLevel.this.players.remove(entityplayer); -@@ -1895,6 +2126,14 @@ +@@ -1895,6 +2134,14 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); 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 index 525e6fc399..b04a563fc0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/AgeableMob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/AgeableMob.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/AgeableMob.java +++ b/net/minecraft/world/entity/AgeableMob.java -@@ -21,6 +21,7 @@ +@@ -21,12 +21,38 @@ protected int age; protected int forcedAge; protected int forcedAgeTimer; @@ -8,7 +8,38 @@ protected AgeableMob(EntityType type, Level world) { super(type, world); -@@ -104,6 +105,7 @@ + } + ++ // Spigot start + @Override ++ public void inactiveTick() ++ { ++ super.inactiveTick(); ++ if ( this.level().isClientSide || this.ageLocked ) ++ { // CraftBukkit ++ this.refreshDimensions(); ++ } else ++ { ++ int i = this.getAge(); ++ ++ if ( i < 0 ) ++ { ++ ++i; ++ this.setAge( i ); ++ } else if ( i > 0 ) ++ { ++ --i; ++ this.setAge( i ); ++ } ++ } ++ } ++ // Spigot end ++ ++ @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { + if (entityData == null) { + entityData = new AgeableMob.AgeableMobGroupData(true); +@@ -104,6 +130,7 @@ super.addAdditionalSaveData(nbt); nbt.putInt("Age", this.getAge()); nbt.putInt("ForcedAge", this.forcedAge); @@ -16,7 +47,7 @@ } @Override -@@ -111,6 +113,7 @@ +@@ -111,6 +138,7 @@ super.readAdditionalSaveData(nbt); this.setAge(nbt.getInt("Age")); this.forcedAge = nbt.getInt("ForcedAge"); @@ -24,7 +55,7 @@ } @Override -@@ -125,7 +128,7 @@ +@@ -125,7 +153,7 @@ @Override public void aiStep() { super.aiStep(); 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 3ec6f8cfc8..835489e22c 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 @@ -22,7 +22,27 @@ @Nullable public UUID ownerUUID; -@@ -200,7 +206,7 @@ +@@ -145,7 +151,19 @@ + this.duration = duration; + } + ++ // Spigot start - copied from below + @Override ++ public void inactiveTick() { ++ super.inactiveTick(); ++ ++ if (this.tickCount >= this.waitTime + this.duration) { ++ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause ++ return; ++ } ++ } ++ // Spigot end ++ ++ @Override + public void tick() { + super.tick(); + Level world = this.level(); +@@ -200,7 +218,7 @@ private void serverTick(ServerLevel world) { if (this.tickCount >= this.waitTime + this.duration) { @@ -31,7 +51,7 @@ } else { boolean flag = this.isWaiting(); boolean flag1 = this.tickCount < this.waitTime; -@@ -215,7 +221,7 @@ +@@ -215,7 +233,7 @@ if (this.radiusPerTick != 0.0F) { f += this.radiusPerTick; if (f < 0.5F) { @@ -40,7 +60,7 @@ return; } -@@ -244,16 +250,17 @@ +@@ -244,16 +262,17 @@ } list.addAll(this.potionContents.customEffects()); @@ -61,7 +81,7 @@ Objects.requireNonNull(entityliving); if (!stream.noneMatch(entityliving::canBeAffected)) { -@@ -262,6 +269,19 @@ +@@ -262,6 +281,19 @@ double d2 = d0 * d0 + d1 * d1; if (d2 <= (double) (f * f)) { @@ -81,7 +101,7 @@ this.victims.put(entityliving, this.tickCount + this.reapplicationDelay); Iterator iterator2 = list.iterator(); -@@ -271,14 +291,14 @@ +@@ -271,14 +303,14 @@ if (((MobEffect) mobeffect1.getEffect().value()).isInstantenous()) { ((MobEffect) mobeffect1.getEffect().value()).applyInstantenousEffect(world, this, this.getOwner(), entityliving, mobeffect1.getAmplifier(), 0.5D); } else { @@ -98,7 +118,7 @@ return; } -@@ -288,7 +308,7 @@ +@@ -288,7 +320,7 @@ if (this.durationOnUse != 0) { this.duration += this.durationOnUse; if (this.duration <= 0) { @@ -107,7 +127,7 @@ return; } } -@@ -336,14 +356,14 @@ +@@ -336,14 +368,14 @@ this.waitTime = waitTime; } @@ -124,7 +144,7 @@ if (this.owner != null && !this.owner.isRemoved()) { return this.owner; } else { -@@ -353,10 +373,10 @@ +@@ -353,10 +385,10 @@ if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; Entity entity = worldserver.getEntity(this.ownerUUID); 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 092c71cb8f..61b2c21d59 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 @@ -96,7 +96,7 @@ private static final EntityDataAccessor DATA_TICKS_FROZEN = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT); private EntityInLevelCallback levelCallback; private final VecDeltaCodec packetPositionCodec; -@@ -253,7 +312,32 @@ +@@ -253,6 +312,37 @@ private final List movementThisTick; private final Set blocksInside; private final LongSet visitedBlocks; @@ -116,7 +116,13 @@ + // Main use case currently is for SPIGOT-7487, preventing dropping of leash when leash is removed + public boolean pluginRemoved = false; + public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot - ++ // Spigot start ++ public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); ++ public final boolean defaultActivationState; ++ public long activatedTick = Integer.MIN_VALUE; ++ public void inactiveTick() { } ++ // Spigot end ++ + public float getBukkitYaw() { + return this.yRot; + } @@ -125,11 +131,24 @@ + return this.level.hasChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); + } + // CraftBukkit end -+ + public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); - this.passengers = ImmutableList.of(); -@@ -292,7 +376,7 @@ +@@ -284,6 +374,13 @@ + this.position = Vec3.ZERO; + this.blockPosition = BlockPos.ZERO; + this.chunkPosition = ChunkPos.ZERO; ++ // Spigot start ++ if (world != null) { ++ this.defaultActivationState = org.spigotmc.ActivationRange.initializeEntityActivationState(this, world.spigotConfig); ++ } else { ++ this.defaultActivationState = false; ++ } ++ // Spigot end + SynchedEntityData.Builder datawatcher_a = new SynchedEntityData.Builder(this); + + datawatcher_a.define(Entity.DATA_SHARED_FLAGS_ID, (byte) 0); +@@ -292,7 +389,7 @@ datawatcher_a.define(Entity.DATA_CUSTOM_NAME, Optional.empty()); datawatcher_a.define(Entity.DATA_SILENT, false); datawatcher_a.define(Entity.DATA_NO_GRAVITY, false); @@ -138,7 +157,7 @@ datawatcher_a.define(Entity.DATA_TICKS_FROZEN, 0); this.defineSynchedData(datawatcher_a); this.entityData = datawatcher_a.build(); -@@ -362,20 +446,36 @@ +@@ -362,20 +459,36 @@ } public void kill(ServerLevel world) { @@ -177,7 +196,7 @@ public boolean equals(Object object) { return object instanceof Entity ? ((Entity) object).id == this.id : false; } -@@ -385,22 +485,34 @@ +@@ -385,22 +498,34 @@ } public void remove(Entity.RemovalReason reason) { @@ -217,7 +236,7 @@ return this.getPose() == pose; } -@@ -417,6 +529,33 @@ +@@ -417,6 +542,33 @@ } public void setRot(float yaw, float pitch) { @@ -251,7 +270,7 @@ this.setYRot(yaw % 360.0F); this.setXRot(pitch % 360.0F); } -@@ -462,6 +601,15 @@ +@@ -462,6 +614,15 @@ this.baseTick(); } @@ -267,7 +286,7 @@ public void baseTick() { ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -475,7 +623,7 @@ +@@ -475,7 +636,7 @@ --this.boardingCooldown; } @@ -276,7 +295,7 @@ if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } -@@ -514,6 +662,10 @@ +@@ -514,6 +675,10 @@ if (this.isInLava()) { this.lavaHurt(); this.fallDistance *= 0.5F; @@ -287,7 +306,7 @@ } this.checkBelowWorld(); -@@ -525,7 +677,7 @@ +@@ -525,7 +690,7 @@ world = this.level(); if (world instanceof ServerLevel worldserver) { if (this instanceof Leashable) { @@ -296,7 +315,7 @@ } } -@@ -568,15 +720,32 @@ +@@ -568,15 +733,32 @@ public void lavaHurt() { if (!this.fireImmune()) { @@ -331,7 +350,7 @@ } } -@@ -587,9 +756,25 @@ +@@ -587,9 +769,25 @@ } public final void igniteForSeconds(float seconds) { @@ -358,7 +377,7 @@ public void igniteForTicks(int ticks) { if (this.remainingFireTicks < ticks) { this.setRemainingFireTicks(ticks); -@@ -610,7 +795,7 @@ +@@ -610,7 +808,7 @@ } protected void onBelowWorld() { @@ -367,7 +386,7 @@ } public boolean isFree(double offsetX, double offsetY, double offsetZ) { -@@ -672,6 +857,7 @@ +@@ -672,6 +870,7 @@ } public void move(MoverType type, Vec3 movement) { @@ -375,10 +394,13 @@ if (this.noPhysics) { this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { -@@ -750,6 +936,28 @@ - } - } +@@ -747,8 +946,30 @@ + if (movement.y != vec3d1.y) { + block.updateEntityMovementAfterFallOn(this.level(), this); ++ } ++ } ++ + // CraftBukkit start + if (this.horizontalCollision && this.getBukkitEntity() instanceof Vehicle) { + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); @@ -392,19 +414,18 @@ + bl = bl.getRelative(BlockFace.SOUTH); + } else if (movement.z < vec3d1.z) { + bl = bl.getRelative(BlockFace.NORTH); -+ } + } + + if (!bl.getType().isAir()) { + VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl); + this.level.getCraftServer().getPluginManager().callEvent(event); + } -+ } + } + // CraftBukkit end -+ + if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { Entity.MovementEmission entity_movementemission = this.getMovementEmission(); - -@@ -764,6 +972,7 @@ +@@ -764,6 +985,7 @@ gameprofilerfiller.pop(); } } @@ -412,10 +433,11 @@ } private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) { -@@ -1132,6 +1341,20 @@ +@@ -1131,8 +1353,22 @@ + protected SoundEvent getSwimHighSpeedSplashSound() { return SoundEvents.GENERIC_SPLASH; - } ++ } + + // CraftBukkit start - Add delegate methods + public SoundEvent getSwimSound0() { @@ -424,16 +446,17 @@ + + public SoundEvent getSwimSplashSound0() { + return this.getSwimSplashSound(); -+ } -+ + } + + public SoundEvent getSwimHighSpeedSplashSound0() { + return this.getSwimHighSpeedSplashSound(); + } + // CraftBukkit end - ++ public void recordMovementThroughBlocks(Vec3 oldPos, Vec3 newPos) { this.movementThisTick.add(new Entity.Movement(oldPos, newPos)); -@@ -1609,6 +1832,7 @@ + } +@@ -1609,6 +1845,7 @@ this.yo = y; this.zo = d4; this.setPos(d3, y, d4); @@ -441,20 +464,21 @@ } public void moveTo(Vec3 pos) { -@@ -1861,6 +2085,12 @@ - return false; - } +@@ -1859,7 +2096,13 @@ + public boolean isPushable() { + return false; ++ } ++ + // CraftBukkit start - collidable API + public boolean canCollideWithBukkit(Entity entity) { + return this.isPushable(); -+ } + } + // CraftBukkit end -+ + public void awardKillScore(Entity entityKilled, DamageSource damageSource) { if (entityKilled instanceof ServerPlayer) { - CriteriaTriggers.ENTITY_KILLED_PLAYER.trigger((ServerPlayer) entityKilled, this, damageSource); -@@ -1889,16 +2119,22 @@ +@@ -1889,16 +2132,22 @@ } public boolean saveAsPassenger(CompoundTag nbt) { @@ -480,7 +504,7 @@ return true; } } -@@ -1909,54 +2145,97 @@ +@@ -1909,54 +2158,97 @@ } public CompoundTag saveWithoutId(CompoundTag nbt) { @@ -598,7 +622,7 @@ } ListTag nbttaglist; -@@ -1972,10 +2251,10 @@ +@@ -1972,10 +2264,10 @@ nbttaglist.add(StringTag.valueOf(s)); } @@ -611,7 +635,7 @@ if (this.isVehicle()) { nbttaglist = new ListTag(); iterator = this.getPassengers().iterator(); -@@ -1984,17 +2263,22 @@ +@@ -1984,17 +2276,22 @@ Entity entity = (Entity) iterator.next(); CompoundTag nbttagcompound1 = new CompoundTag(); @@ -637,7 +661,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being saved"); -@@ -2080,6 +2364,45 @@ +@@ -2080,6 +2377,45 @@ } else { throw new IllegalStateException("Entity has invalid position"); } @@ -683,7 +707,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded"); -@@ -2101,6 +2424,12 @@ +@@ -2101,6 +2437,12 @@ return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null; } @@ -696,7 +720,7 @@ protected abstract void readAdditionalSaveData(CompoundTag nbt); protected abstract void addAdditionalSaveData(CompoundTag nbt); -@@ -2153,9 +2482,22 @@ +@@ -2153,9 +2495,22 @@ if (stack.isEmpty()) { return null; } else { @@ -719,7 +743,7 @@ world.addFreshEntity(entityitem); return entityitem; } -@@ -2184,6 +2526,12 @@ +@@ -2184,6 +2539,12 @@ if (this.isAlive() && this instanceof Leashable leashable) { if (leashable.getLeashHolder() == player) { if (!this.level().isClientSide()) { @@ -732,7 +756,7 @@ if (player.hasInfiniteMaterials()) { leashable.removeLeash(); } else { -@@ -2200,6 +2548,13 @@ +@@ -2200,6 +2561,13 @@ if (itemstack.is(Items.LEAD) && leashable.canHaveALeashAttachedToIt()) { if (!this.level().isClientSide()) { @@ -746,7 +770,7 @@ leashable.setLeashedTo(player, true); } -@@ -2265,7 +2620,7 @@ +@@ -2265,7 +2633,7 @@ } public boolean showVehicleHealth() { @@ -755,7 +779,7 @@ } public boolean startRiding(Entity entity, boolean force) { -@@ -2273,7 +2628,7 @@ +@@ -2273,7 +2641,7 @@ return false; } else if (!entity.couldAcceptPassenger()) { return false; @@ -764,7 +788,7 @@ return false; } else { for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) { -@@ -2285,11 +2640,32 @@ +@@ -2285,11 +2653,32 @@ if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) { return false; } else { @@ -798,7 +822,7 @@ this.vehicle = entity; this.vehicle.addPassenger(this); entity.getIndirectPassengersStream().filter((entity2) -> { -@@ -2318,7 +2694,7 @@ +@@ -2318,7 +2707,7 @@ Entity entity = this.vehicle; this.vehicle = null; @@ -807,7 +831,7 @@ } } -@@ -2349,21 +2725,50 @@ +@@ -2349,21 +2738,50 @@ } } @@ -864,7 +888,7 @@ } protected boolean canAddPassenger(Entity passenger) { -@@ -2464,7 +2869,7 @@ +@@ -2464,7 +2882,7 @@ if (teleporttransition != null) { ServerLevel worldserver1 = teleporttransition.newLevel(); @@ -873,7 +897,7 @@ this.teleport(teleporttransition); } } -@@ -2547,7 +2952,7 @@ +@@ -2547,7 +2965,7 @@ } public boolean isCrouching() { @@ -882,7 +906,7 @@ } public boolean isSprinting() { -@@ -2563,7 +2968,7 @@ +@@ -2563,7 +2981,7 @@ } public boolean isVisuallySwimming() { @@ -891,7 +915,7 @@ } public boolean isVisuallyCrawling() { -@@ -2571,6 +2976,13 @@ +@@ -2571,6 +2989,13 @@ } public void setSwimming(boolean swimming) { @@ -905,7 +929,7 @@ this.setSharedFlag(4, swimming); } -@@ -2624,8 +3036,12 @@ +@@ -2624,8 +3049,12 @@ return this.getTeam() != null ? this.getTeam().isAlliedTo(team) : false; } @@ -919,7 +943,7 @@ } public boolean getSharedFlag(int index) { -@@ -2644,7 +3060,7 @@ +@@ -2644,7 +3073,7 @@ } public int getMaxAirSupply() { @@ -928,7 +952,7 @@ } public int getAirSupply() { -@@ -2652,7 +3068,18 @@ +@@ -2652,7 +3081,18 @@ } public void setAirSupply(int air) { @@ -948,7 +972,7 @@ } public int getTicksFrozen() { -@@ -2679,11 +3106,40 @@ +@@ -2679,11 +3119,40 @@ public void thunderHit(ServerLevel world, LightningBolt lightning) { this.setRemainingFireTicks(this.remainingFireTicks + 1); @@ -991,7 +1015,7 @@ } public void onAboveBubbleCol(boolean drag) { -@@ -2713,7 +3169,7 @@ +@@ -2713,7 +3182,7 @@ this.resetFallDistance(); } @@ -1000,7 +1024,7 @@ return true; } -@@ -2852,6 +3308,18 @@ +@@ -2852,6 +3321,18 @@ if (world instanceof ServerLevel worldserver) { if (!this.isRemoved()) { @@ -1019,7 +1043,7 @@ ServerLevel worldserver1 = teleportTarget.newLevel(); boolean flag = worldserver1.dimension() != worldserver.dimension(); -@@ -2920,8 +3388,12 @@ +@@ -2920,8 +3401,12 @@ } else { entity.restoreFrom(this); this.removeAfterChangingDimensions(); @@ -1033,7 +1057,7 @@ Iterator iterator1 = list1.iterator(); while (iterator1.hasNext()) { -@@ -2947,7 +3419,7 @@ +@@ -2947,7 +3432,7 @@ } private void sendTeleportTransitionToRidingPlayers(TeleportTransition teleportTarget) { @@ -1042,7 +1066,7 @@ Iterator iterator = this.getIndirectPassengers().iterator(); while (iterator.hasNext()) { -@@ -2995,8 +3467,9 @@ +@@ -2995,8 +3480,9 @@ } protected void removeAfterChangingDimensions() { @@ -1053,12 +1077,10 @@ leashable.removeLeash(); } -@@ -3004,7 +3477,21 @@ - - public Vec3 getRelativePortalPosition(Direction.Axis portalAxis, BlockUtil.FoundRectangle portalRect) { +@@ -3006,6 +3492,20 @@ return PortalShape.getRelativePosition(portalRect, portalAxis, this.position(), this.getDimensions(this.getPose())); -+ } -+ + } + + // CraftBukkit start + public CraftPortalEvent callPortalEvent(Entity entity, Location exit, PlayerTeleportEvent.TeleportCause cause, int searchRadius, int creationRadius) { + org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); @@ -1070,12 +1092,13 @@ + return null; + } + return new CraftPortalEvent(event); - } ++ } + // CraftBukkit end - ++ public boolean canUsePortal(boolean allowVehicles) { return (allowVehicles || !this.isPassenger()) && this.isAlive(); -@@ -3134,10 +3621,16 @@ + } +@@ -3134,9 +3634,15 @@ return (Boolean) this.entityData.get(Entity.DATA_CUSTOM_NAME_VISIBLE); } @@ -1086,16 +1109,15 @@ + public final boolean teleportTo(ServerLevel world, double destX, double destY, double destZ, Set flags, float yaw, float pitch, boolean resetCamera) { + return this.teleportTo(world, destX, destY, destZ, flags, yaw, pitch, resetCamera, PlayerTeleportEvent.TeleportCause.UNKNOWN); + } - ++ + public boolean teleportTo(ServerLevel worldserver, double d0, double d1, double d2, Set set, float f, float f1, boolean flag, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { + float f2 = Mth.clamp(f1, -90.0F, 90.0F); + Entity entity = this.teleport(new TeleportTransition(worldserver, new Vec3(d0, d1, d2), Vec3.ZERO, f, f2, set, TeleportTransition.DO_NOTHING, cause)); + // CraftBukkit end -+ + return entity != null; } - -@@ -3187,7 +3680,7 @@ +@@ -3187,7 +3693,7 @@ /** @deprecated */ @Deprecated protected void fixupDimensions() { @@ -1104,7 +1126,7 @@ EntityDimensions entitysize = this.getDimensions(entitypose); this.dimensions = entitysize; -@@ -3196,7 +3689,7 @@ +@@ -3196,7 +3702,7 @@ public void refreshDimensions() { EntityDimensions entitysize = this.dimensions; @@ -1113,7 +1135,7 @@ EntityDimensions entitysize1 = this.getDimensions(entitypose); this.dimensions = entitysize1; -@@ -3258,10 +3751,29 @@ +@@ -3258,10 +3764,29 @@ } public final void setBoundingBox(AABB boundingBox) { @@ -1145,7 +1167,7 @@ return this.getDimensions(pose).eyeHeight(); } -@@ -3335,7 +3847,7 @@ +@@ -3335,7 +3860,7 @@ } @Nullable @@ -1154,7 +1176,7 @@ return null; } -@@ -3435,7 +3947,7 @@ +@@ -3435,7 +3960,7 @@ } public boolean isControlledByLocalInstance() { @@ -1163,7 +1185,7 @@ if (entityliving instanceof Player entityhuman) { return entityhuman.isLocalPlayer(); -@@ -3445,7 +3957,7 @@ +@@ -3445,7 +3970,7 @@ } public boolean isControlledByClient() { @@ -1172,7 +1194,7 @@ return entityliving != null && entityliving.isControlledByClient(); } -@@ -3463,7 +3975,7 @@ +@@ -3463,7 +3988,7 @@ return new Vec3((double) f1 * d2 / (double) f3, 0.0D, (double) f2 * d2 / (double) f3); } @@ -1181,7 +1203,7 @@ return new Vec3(this.getX(), this.getBoundingBox().maxY, this.getZ()); } -@@ -3489,8 +4001,37 @@ +@@ -3489,8 +4014,37 @@ return 1; } @@ -1220,19 +1242,20 @@ } public void lookAt(EntityAnchorArgument.Anchor anchorPoint, Vec3 target) { -@@ -3551,6 +4092,11 @@ +@@ -3550,7 +4104,12 @@ + vec3d = vec3d.add(vec3d1); ++k1; - } ++ } + // CraftBukkit start - store last lava contact location + if (tag == FluidTags.LAVA) { + this.lastLavaContact = blockposition_mutableblockposition.immutable(); -+ } + } + // CraftBukkit end } } } -@@ -3613,7 +4159,7 @@ +@@ -3613,7 +4172,7 @@ return new ClientboundAddEntityPacket(this, entityTrackerEntry); } @@ -1241,7 +1264,7 @@ return this.type.getDimensions(); } -@@ -3818,8 +4364,16 @@ +@@ -3818,8 +4377,16 @@ @Override public final void setRemoved(Entity.RemovalReason reason) { @@ -1259,7 +1282,7 @@ } if (this.removalReason.shouldDestroy()) { -@@ -3827,8 +4381,8 @@ +@@ -3827,8 +4394,8 @@ } this.getPassengers().forEach(Entity::stopRiding); @@ -1270,7 +1293,7 @@ } public void unsetRemoved() { -@@ -3887,7 +4441,7 @@ +@@ -3887,7 +4454,7 @@ } public Vec3 getKnownMovement() { 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 c8dd6f4966..251c921b81 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 @@ -17,10 +17,11 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.item.AxeItem; -@@ -136,6 +137,32 @@ +@@ -135,6 +136,32 @@ + import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Scoreboard; import org.slf4j.Logger; - ++ +// CraftBukkit start +import java.util.ArrayList; +import java.util.HashSet; @@ -46,10 +47,9 @@ +// CraftBukkit end + +import org.bukkit.craftbukkit.SpigotTimings; // Spigot -+ + public abstract class LivingEntity extends Entity implements Attackable { - private static final Logger LOGGER = LogUtils.getLogger(); @@ -174,7 +201,7 @@ public static final float DEFAULT_BABY_SCALE = 0.5F; public static final String ATTRIBUTES_FIELD = "attributes"; @@ -68,7 +68,7 @@ public int lastHurtByPlayerTime; protected boolean dead; protected int noActionTime; -@@ -260,7 +287,20 @@ +@@ -260,7 +287,27 @@ protected boolean skipDropExperience; private final EnumMap>> activeLocationDependentEnchantments; protected float appliedScale; @@ -85,11 +85,18 @@ + return this.getYHeadRot(); + } + // CraftBukkit end ++ // Spigot start ++ public void inactiveTick() ++ { ++ super.inactiveTick(); ++ ++this.noActionTime; // Above all the floats ++ } ++ // Spigot end + protected LivingEntity(EntityType type, Level world) { super(type, world); this.lastHandItemStacks = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -276,7 +316,9 @@ +@@ -276,7 +323,9 @@ this.activeLocationDependentEnchantments = new EnumMap(EquipmentSlot.class); this.appliedScale = 1.0F; this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type)); @@ -100,7 +107,7 @@ this.blocksBuilding = true; this.rotA = (float) ((Math.random() + 1.0D) * 0.009999999776482582D); this.reapplyPosition(); -@@ -356,7 +398,13 @@ +@@ -356,7 +405,13 @@ double d8 = Math.min((double) (0.2F + f / 15.0F), 2.5D); int i = (int) (150.0D * d8); @@ -115,7 +122,7 @@ } } } -@@ -402,7 +450,7 @@ +@@ -402,7 +457,7 @@ } if (this.isAlive()) { @@ -124,7 +131,7 @@ Level world1 = this.level(); ServerLevel worldserver1; double d0; -@@ -424,7 +472,7 @@ +@@ -424,7 +479,7 @@ } if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { @@ -133,7 +140,7 @@ if (flag1) { this.setAirSupply(this.decreaseAirSupply(this.getAirSupply())); -@@ -573,7 +621,7 @@ +@@ -573,7 +628,7 @@ ++this.deathTime; if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) { this.level().broadcastEntityEvent(this, (byte) 60); @@ -142,7 +149,7 @@ } } -@@ -629,7 +677,7 @@ +@@ -629,7 +684,7 @@ return this.lastHurtByMobTimestamp; } @@ -151,27 +158,28 @@ this.lastHurtByPlayer = attacking; this.lastHurtByPlayerTime = this.tickCount; } -@@ -679,17 +727,23 @@ +@@ -679,17 +734,23 @@ } public void onEquipItem(EquipmentSlot slot, ItemStack oldStack, ItemStack newStack) { +- if (!this.level().isClientSide() && !this.isSpectator()) { +- boolean flag = newStack.isEmpty() && oldStack.isEmpty(); + // CraftBukkit start + this.onEquipItem(slot, oldStack, newStack, false); + } -+ -+ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) { -+ // CraftBukkit end - if (!this.level().isClientSide() && !this.isSpectator()) { -- boolean flag = newStack.isEmpty() && oldStack.isEmpty(); -+ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty(); - if (!flag && !ItemStack.isSameItemSameComponents(oldStack, newStack) && !this.firstTick) { - Equippable equippable = (Equippable) newStack.get(DataComponents.EQUIPPABLE); -+ if (!flag && !ItemStack.isSameItemSameComponents(itemstack, itemstack1) && !this.firstTick) { -+ Equippable equippable = (Equippable) itemstack1.get(DataComponents.EQUIPPABLE); ++ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) { ++ // CraftBukkit end ++ if (!this.level().isClientSide() && !this.isSpectator()) { ++ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty(); - if (!this.isSilent() && equippable != null && slot == equippable.slot()) { - this.level().playSeededSound((Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong()); ++ if (!flag && !ItemStack.isSameItemSameComponents(itemstack, itemstack1) && !this.firstTick) { ++ Equippable equippable = (Equippable) itemstack1.get(DataComponents.EQUIPPABLE); ++ + if (!this.isSilent() && equippable != null && enumitemslot == equippable.slot() && !silent) { // CraftBukkit + this.level().playSeededSound((net.minecraft.world.entity.player.Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong()); } @@ -181,7 +189,7 @@ this.gameEvent(equippable != null ? GameEvent.EQUIP : GameEvent.UNEQUIP); } -@@ -699,17 +753,24 @@ +@@ -699,17 +760,24 @@ @Override public void remove(Entity.RemovalReason reason) { @@ -209,7 +217,7 @@ this.brain.clearMemories(); } -@@ -722,6 +783,7 @@ +@@ -722,6 +790,7 @@ mobeffect.onMobRemoved(world, this, reason); } @@ -217,7 +225,7 @@ this.activeEffects.clear(); } -@@ -781,6 +843,17 @@ +@@ -781,6 +850,17 @@ } } @@ -235,7 +243,7 @@ if (nbt.contains("Health", 99)) { this.setHealth(nbt.getFloat("Health")); } -@@ -819,9 +892,32 @@ +@@ -819,9 +899,32 @@ } @@ -268,7 +276,7 @@ try { while (iterator.hasNext()) { Holder holder = (Holder) iterator.next(); -@@ -831,6 +927,12 @@ +@@ -831,6 +934,12 @@ this.onEffectUpdated(mobeffect, true, (Entity) null); })) { if (!this.level().isClientSide) { @@ -281,7 +289,7 @@ iterator.remove(); this.onEffectsRemoved(List.of(mobeffect)); } -@@ -841,6 +943,17 @@ +@@ -841,6 +950,17 @@ } catch (ConcurrentModificationException concurrentmodificationexception) { ; } @@ -299,7 +307,7 @@ if (this.effectsDirty) { if (!this.level().isClientSide) { -@@ -921,7 +1034,7 @@ +@@ -921,7 +1041,7 @@ } public boolean canAttack(LivingEntity target) { @@ -308,7 +316,7 @@ } public boolean canBeSeenAsEnemy() { -@@ -952,17 +1065,36 @@ +@@ -952,17 +1072,36 @@ this.entityData.set(LivingEntity.DATA_EFFECT_PARTICLES, List.of()); } @@ -349,7 +357,7 @@ } } -@@ -987,24 +1119,55 @@ +@@ -987,24 +1126,55 @@ return this.addEffect(effect, (Entity) null); } @@ -378,9 +386,6 @@ + MobEffectInstance mobeffect1 = (MobEffectInstance) this.activeEffects.get(mobeffect.getEffect()); boolean flag = false; -- if (mobeffect1 == null) { -- this.activeEffects.put(effect.getEffect(), effect); -- this.onEffectAdded(effect, source); + // CraftBukkit start + boolean override = false; + if (mobeffect1 != null) { @@ -393,7 +398,9 @@ + } + // CraftBukkit end + -+ if (mobeffect1 == null) { + if (mobeffect1 == null) { +- this.activeEffects.put(effect.getEffect(), effect); +- this.onEffectAdded(effect, source); + this.activeEffects.put(mobeffect.getEffect(), mobeffect); + this.onEffectAdded(mobeffect, entity); flag = true; @@ -414,7 +421,7 @@ return flag; } } -@@ -1031,14 +1194,40 @@ +@@ -1031,14 +1201,40 @@ return this.getType().is(EntityTypeTags.INVERTED_HEALING_AND_HARM); } @@ -457,7 +464,7 @@ if (mobeffect != null) { this.onEffectsRemoved(List.of(mobeffect)); return true; -@@ -1142,20 +1331,55 @@ +@@ -1142,20 +1338,55 @@ } @@ -514,7 +521,7 @@ this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1167,7 +1391,7 @@ +@@ -1167,7 +1398,7 @@ public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { if (this.isInvulnerableTo(world, source)) { return false; @@ -523,7 +530,7 @@ return false; } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1182,10 +1406,11 @@ +@@ -1182,10 +1413,11 @@ } float f1 = amount; @@ -537,7 +544,7 @@ this.hurtCurrentlyUsedShield(amount); f2 = amount; amount = 0.0F; -@@ -1202,15 +1427,26 @@ +@@ -1202,15 +1434,26 @@ flag = true; } @@ -566,7 +573,7 @@ this.walkAnimation.setSpeed(1.5F); if (Float.isNaN(amount) || Float.isInfinite(amount)) { amount = Float.MAX_VALUE; -@@ -1218,18 +1454,27 @@ +@@ -1218,18 +1461,27 @@ boolean flag1 = true; @@ -598,7 +605,7 @@ this.hurtDuration = 10; this.hurtTime = this.hurtDuration; } -@@ -1243,7 +1488,7 @@ +@@ -1243,7 +1495,7 @@ world.broadcastDamageEvent(this, source); } @@ -607,7 +614,7 @@ this.markHurt(); } -@@ -1263,7 +1508,7 @@ +@@ -1263,7 +1515,7 @@ d1 = source.getSourcePosition().z() - this.getZ(); } @@ -616,7 +623,7 @@ if (!flag) { this.indicateDamage(d0, d1); } -@@ -1282,7 +1527,7 @@ +@@ -1282,7 +1534,7 @@ this.playHurtSound(source); } @@ -625,7 +632,7 @@ if (flag2) { this.lastDamageSource = source; -@@ -1329,10 +1574,10 @@ +@@ -1329,10 +1581,10 @@ } @Nullable @@ -638,7 +645,7 @@ this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = entityhuman; return entityhuman; -@@ -1342,8 +1587,8 @@ +@@ -1342,8 +1594,8 @@ this.lastHurtByPlayerTime = 100; LivingEntity entityliving = entitywolf.getOwner(); @@ -649,7 +656,7 @@ this.lastHurtByPlayer = entityhuman1; } else { -@@ -1363,7 +1608,7 @@ +@@ -1363,7 +1615,7 @@ } protected void blockedByShield(LivingEntity target) { @@ -658,7 +665,7 @@ } private boolean checkTotemDeathProtection(DamageSource source) { -@@ -1375,20 +1620,33 @@ +@@ -1375,20 +1627,33 @@ InteractionHand[] aenumhand = InteractionHand.values(); int i = aenumhand.length; @@ -696,7 +703,7 @@ ServerPlayer entityplayer = (ServerPlayer) this; entityplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -@@ -1512,14 +1770,22 @@ +@@ -1512,14 +1777,22 @@ BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) { @@ -721,7 +728,7 @@ this.level().addFreshEntity(entityitem); } } -@@ -1530,22 +1796,37 @@ +@@ -1530,24 +1803,39 @@ protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { boolean flag = this.lastHurtByPlayerTime > 0; @@ -751,8 +758,8 @@ } + return 0; // CraftBukkit -+ } -+ + } + + protected void dropExperience(ServerLevel world, @Nullable Entity attacker) { + // CraftBukkit start - Update getExpReward() above if the removed if() changes! + if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time @@ -760,10 +767,12 @@ + this.expToDrop = 0; + } + // CraftBukkit end - } - ++ } ++ protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {} -@@ -1612,19 +1893,31 @@ + + public long getLootTableSeed() { +@@ -1612,19 +1900,31 @@ } public void knockback(double strength, double x, double z) { @@ -802,7 +811,7 @@ } } -@@ -1683,6 +1976,20 @@ +@@ -1683,6 +1983,20 @@ return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL); } @@ -823,7 +832,7 @@ public Optional getLastClimbablePos() { return this.lastClimbablePos; } -@@ -1757,9 +2064,14 @@ +@@ -1757,9 +2071,14 @@ int i = this.calculateFallDamage(fallDistance, damageMultiplier); if (i > 0) { @@ -839,7 +848,7 @@ return true; } else { return flag; -@@ -1830,7 +2142,7 @@ +@@ -1830,7 +2149,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) { if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -848,7 +857,7 @@ amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); } -@@ -1841,7 +2153,8 @@ +@@ -1841,7 +2160,8 @@ if (source.is(DamageTypeTags.BYPASSES_EFFECTS)) { return amount; } else { @@ -858,7 +867,7 @@ int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = amount * (float) j; -@@ -1884,18 +2197,144 @@ +@@ -1884,18 +2204,144 @@ } } @@ -1012,7 +1021,7 @@ if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1904,13 +2343,48 @@ +@@ -1904,13 +2350,48 @@ } } @@ -1065,7 +1074,7 @@ } public CombatTracker getCombatTracker() { -@@ -1935,8 +2409,18 @@ +@@ -1935,8 +2416,18 @@ } public final void setArrowCount(int stuckArrowCount) { @@ -1085,7 +1094,7 @@ public final int getStingerCount() { return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID); -@@ -1999,7 +2483,7 @@ +@@ -1999,7 +2490,7 @@ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); } @@ -1094,20 +1103,20 @@ this.setHealth(0.0F); this.die(this.damageSources().generic()); } -@@ -2182,6 +2666,12 @@ +@@ -2181,6 +2672,12 @@ + public abstract Iterable getArmorSlots(); public abstract ItemStack getItemBySlot(EquipmentSlot slot); - ++ + // CraftBukkit start + public void setItemSlot(EquipmentSlot enumitemslot, ItemStack itemstack, boolean silent) { + this.setItemSlot(enumitemslot, itemstack); + } + // CraftBukkit end -+ + public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack); - public Iterable getHandSlots() { -@@ -2494,7 +2984,7 @@ +@@ -2494,7 +2991,7 @@ } @@ -1116,7 +1125,7 @@ Vec3 vec3d1 = this.getRiddenInput(controllingPlayer, movementInput); this.tickRidden(controllingPlayer, vec3d1); -@@ -2507,13 +2997,13 @@ +@@ -2507,13 +3004,13 @@ } @@ -1133,7 +1142,7 @@ return this.getSpeed(); } -@@ -2571,7 +3061,7 @@ +@@ -2571,7 +3068,7 @@ double d1 = Mth.clamp(motion.z, -0.15000000596046448D, 0.15000000596046448D); double d2 = Math.max(motion.y, -0.15000000596046448D); @@ -1142,7 +1151,7 @@ d2 = 0.0D; } -@@ -2586,7 +3076,7 @@ +@@ -2586,7 +3083,7 @@ } protected float getFlyingSpeed() { @@ -1151,7 +1160,7 @@ } public float getSpeed() { -@@ -2604,6 +3094,7 @@ +@@ -2604,6 +3101,7 @@ @Override public void tick() { @@ -1159,7 +1168,7 @@ super.tick(); this.updatingUsingItem(); this.updateSwimAmount(); -@@ -2634,7 +3125,7 @@ +@@ -2634,7 +3132,7 @@ } } @@ -1168,7 +1177,7 @@ if (this.tickCount % 20 == 0) { this.getCombatTracker().recheckStatus(); } -@@ -2645,7 +3136,9 @@ +@@ -2645,7 +3143,9 @@ } if (!this.isRemoved()) { @@ -1178,7 +1187,7 @@ } double d0 = this.getX() - this.xo; -@@ -2739,9 +3232,10 @@ +@@ -2739,9 +3239,10 @@ } this.elytraAnimationState.tick(); @@ -1190,7 +1199,7 @@ Map map = this.collectEquipmentChanges(); if (map != null) { -@@ -2945,6 +3439,7 @@ +@@ -2945,6 +3446,7 @@ ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("ai"); @@ -1198,7 +1207,7 @@ if (this.isImmobile()) { this.jumping = false; this.xxa = 0.0F; -@@ -2954,6 +3449,7 @@ +@@ -2954,6 +3456,7 @@ this.serverAiStep(); gameprofilerfiller.pop(); } @@ -1206,7 +1215,7 @@ gameprofilerfiller.pop(); gameprofilerfiller.push("jump"); -@@ -2996,11 +3492,12 @@ +@@ -2996,11 +3499,12 @@ this.resetFallDistance(); } @@ -1220,7 +1229,7 @@ if (this.isAlive()) { this.travelRidden(entityhuman, vec3d1); break label112; -@@ -3009,6 +3506,7 @@ +@@ -3009,6 +3513,7 @@ this.travel(vec3d1); } @@ -1228,7 +1237,7 @@ if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { this.applyEffectsFromBlocks(); -@@ -3044,7 +3542,9 @@ +@@ -3044,7 +3549,9 @@ this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); } @@ -1238,7 +1247,7 @@ gameprofilerfiller.pop(); world = this.level(); if (world instanceof ServerLevel worldserver) { -@@ -3063,6 +3563,7 @@ +@@ -3063,6 +3570,7 @@ this.checkSlowFallDistance(); if (!this.level().isClientSide) { if (!this.canGlide()) { @@ -1246,7 +1255,7 @@ this.setSharedFlag(7, false); return; } -@@ -3113,7 +3614,7 @@ +@@ -3113,7 +3621,7 @@ Level world = this.level(); if (!(world instanceof ServerLevel worldserver)) { @@ -1255,7 +1264,7 @@ } else { List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); -@@ -3305,15 +3806,22 @@ +@@ -3305,15 +3813,22 @@ @Override public boolean isPickable() { @@ -1280,7 +1289,7 @@ public float getYHeadRot() { return this.yHeadRot; } -@@ -3483,8 +3991,31 @@ +@@ -3483,8 +3998,31 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { @@ -1313,7 +1322,7 @@ if (itemstack != this.useItem) { this.setItemInHand(enumhand, itemstack); } -@@ -3568,12 +4099,18 @@ +@@ -3568,12 +4106,18 @@ } public boolean randomTeleport(double x, double y, double z, boolean particleEffects) { @@ -1334,7 +1343,7 @@ Level world = this.level(); if (world.hasChunkAt(blockposition)) { -@@ -3592,18 +4129,43 @@ +@@ -3592,18 +4136,43 @@ } if (flag2) { @@ -1382,7 +1391,7 @@ world.broadcastEntityEvent(this, (byte) 46); } -@@ -3613,7 +4175,7 @@ +@@ -3613,7 +4182,7 @@ entitycreature.getNavigation().stop(); } @@ -1391,7 +1400,7 @@ } } -@@ -3706,7 +4268,7 @@ +@@ -3706,7 +4275,7 @@ } public void stopSleeping() { @@ -1400,7 +1409,7 @@ Level world = this.level(); java.util.Objects.requireNonNull(world); -@@ -3718,9 +4280,9 @@ +@@ -3718,9 +4287,9 @@ this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3); Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> { @@ -1412,7 +1421,7 @@ }); Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize(); float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); -@@ -3740,7 +4302,7 @@ +@@ -3740,7 +4309,7 @@ @Nullable public Direction getBedOrientation() { @@ -1421,7 +1430,7 @@ return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null; } -@@ -3905,7 +4467,7 @@ +@@ -3905,7 +4474,7 @@ public float maxUpStep() { float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT); 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 54a286345b..b9b409b53b 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 @@ -94,7 +94,7 @@ this.hasImpulse |= this.updateInWaterStateAndDoFluidPushing(); if (!this.level().isClientSide) { -@@ -201,8 +214,14 @@ +@@ -201,12 +214,40 @@ } } @@ -110,8 +110,34 @@ + this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } ++ } ++ } ++ ++ // Spigot start - copied from above ++ @Override ++ public void inactiveTick() { ++ // CraftBukkit start - Use wall time for pickup and despawn timers ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks; ++ if (this.age != -32768) this.age += elapsedTicks; ++ this.lastTick = MinecraftServer.currentTick; ++ // CraftBukkit end ++ ++ if (!this.level().isClientSide && this.age >= this.level().spigotConfig.itemDespawnRate) { // Spigot ++ // CraftBukkit start - fire ItemDespawnEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { ++ this.age = 0; ++ return; ++ } ++ // CraftBukkit end ++ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } -@@ -229,7 +248,10 @@ + } ++ // Spigot end + + @Override + public BlockPos getBlockPosBelowThatAffectsMyMovement() { +@@ -229,7 +270,10 @@ private void mergeWithNeighbours() { if (this.isMergable()) { @@ -123,7 +149,7 @@ return entityitem != this && entityitem.isMergable(); }); Iterator iterator = list.iterator(); -@@ -259,7 +281,7 @@ +@@ -259,7 +303,7 @@ ItemStack itemstack1 = other.getItem(); if (Objects.equals(this.target, other.target) && ItemEntity.areMergable(itemstack, itemstack1)) { @@ -132,7 +158,7 @@ ItemEntity.merge(this, itemstack, other, itemstack1); } else { ItemEntity.merge(other, itemstack1, this, itemstack); -@@ -287,11 +309,16 @@ +@@ -287,11 +331,16 @@ } private static void merge(ItemEntity targetEntity, ItemStack targetStack, ItemEntity sourceEntity, ItemStack sourceStack) { @@ -150,7 +176,7 @@ } } -@@ -320,12 +347,17 @@ +@@ -320,12 +369,17 @@ } else if (!this.getItem().canBeHurtBy(source)) { return false; } else { @@ -169,7 +195,7 @@ } return true; -@@ -382,22 +414,62 @@ +@@ -382,22 +436,62 @@ } if (this.getItem().isEmpty()) { @@ -186,7 +212,7 @@ ItemStack itemstack = this.getItem(); Item item = itemstack.getItem(); int i = itemstack.getCount(); -+ + + // CraftBukkit start - fire PlayerPickupItemEvent + int canHold = player.getInventory().canHold(itemstack); + int remaining = i - canHold; @@ -201,7 +227,7 @@ + itemstack.setCount(i); // SPIGOT-5294 - restore count + return; + } - ++ + // Call newer event afterwards + EntityPickupItemEvent entityEvent = new EntityPickupItemEvent((Player) player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); + entityEvent.setCancelled(!entityEvent.getEntity().getCanPickupItems()); @@ -235,7 +261,7 @@ itemstack.setCount(i); } -@@ -492,7 +564,7 @@ +@@ -492,7 +586,7 @@ public void makeFakeItem() { this.setNeverPickUp(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch index 6d6fcf7eac..dbf21d8f36 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch @@ -24,7 +24,26 @@ } @Override -@@ -235,7 +243,7 @@ +@@ -216,7 +224,18 @@ + return this.assignProfessionWhenSpawned; + } + ++ // Spigot Start + @Override ++ public void inactiveTick() { ++ // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :( ++ if (this.level().spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) { ++ this.customServerAiStep((ServerLevel) this.level()); ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ ++ @Override + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + +@@ -235,7 +254,7 @@ this.increaseProfessionLevelOnUpdate = false; } @@ -33,7 +52,7 @@ } } -@@ -360,7 +368,13 @@ +@@ -360,7 +379,13 @@ while (iterator.hasNext()) { MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); @@ -48,7 +67,7 @@ } this.resendOffersToTradingPlayer(); -@@ -429,7 +443,13 @@ +@@ -429,7 +454,13 @@ while (iterator.hasNext()) { MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); @@ -63,7 +82,7 @@ } } -@@ -489,7 +509,7 @@ +@@ -489,7 +520,7 @@ @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); @@ -72,7 +91,7 @@ Logger logger = Villager.LOGGER; Objects.requireNonNull(logger); -@@ -512,7 +532,7 @@ +@@ -512,7 +543,7 @@ public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); if (nbt.contains("VillagerData", 10)) { @@ -81,7 +100,7 @@ Logger logger = Villager.LOGGER; Objects.requireNonNull(logger); -@@ -808,7 +828,7 @@ +@@ -808,7 +839,7 @@ entitywitch1.finalizeSpawn(world, world.getCurrentDifficultyAt(entitywitch1.blockPosition()), EntitySpawnReason.CONVERSION, (SpawnGroupData) null); entitywitch1.setPersistenceRequired(); this.releaseAllPois(); @@ -90,7 +109,7 @@ if (entitywitch == null) { super.thunderHit(world, lightning); -@@ -906,7 +926,7 @@ +@@ -906,7 +937,7 @@ }).limit(5L).toList(); if (list1.size() >= requiredCount) { @@ -99,7 +118,7 @@ list.forEach(GolemSensor::golemDetected); } } -@@ -963,7 +983,7 @@ +@@ -963,7 +994,7 @@ @Override public void startSleeping(BlockPos pos) { super.startSleeping(pos); @@ -108,7 +127,7 @@ this.brain.eraseMemory(MemoryModuleType.WALK_TARGET); this.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); } -@@ -971,7 +991,7 @@ +@@ -971,7 +1002,7 @@ @Override public void stopSleeping() { super.stopSleeping(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch index 283001e049..26c18f6e4c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch @@ -19,7 +19,26 @@ public abstract class AbstractArrow extends Projectile { -@@ -88,23 +93,30 @@ +@@ -78,6 +83,18 @@ + @Nullable + public ItemStack firedFromWeapon; + ++ // Spigot Start ++ @Override ++ public void inactiveTick() ++ { ++ if ( this.isInGround() ) ++ { ++ this.life += 1; ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ + protected AbstractArrow(EntityType type, Level world) { + super(type, world); + this.pickup = AbstractArrow.Pickup.DISALLOWED; +@@ -88,23 +105,30 @@ } protected AbstractArrow(EntityType type, double x, double y, double z, Level world, ItemStack stack, @Nullable ItemStack weapon) { @@ -30,7 +49,7 @@ + // CraftBukkit start - handle the owner before the rest of things + this(type, x, y, z, world, stack, weapon, null); + } - ++ + protected AbstractArrow(EntityType entitytypes, double d0, double d1, double d2, Level world, ItemStack itemstack, @Nullable ItemStack itemstack1, @Nullable LivingEntity ownerEntity) { + this(entitytypes, world); + this.setOwner(ownerEntity); @@ -38,7 +57,7 @@ + this.pickupItemStack = itemstack.copy(); + this.setCustomName((Component) itemstack.get(DataComponents.CUSTOM_NAME)); + Unit unit = (Unit) itemstack.remove(DataComponents.INTANGIBLE_PROJECTILE); -+ + if (unit != null) { this.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; } @@ -59,7 +78,7 @@ if (i > 0) { this.setPierceLevel((byte) i); -@@ -114,8 +126,8 @@ +@@ -114,8 +138,8 @@ } protected AbstractArrow(EntityType type, LivingEntity owner, Level world, ItemStack stack, @Nullable ItemStack shotFrom) { @@ -70,7 +89,7 @@ } public void setSoundEvent(SoundEvent sound) { -@@ -282,7 +294,7 @@ +@@ -282,7 +306,7 @@ if (movingobjectpositionentity == null) { if (this.isAlive() && blockHitResult.getType() != HitResult.Type.MISS) { @@ -79,7 +98,7 @@ this.hasImpulse = true; } } else { -@@ -290,7 +302,7 @@ +@@ -290,7 +314,7 @@ continue; } @@ -88,7 +107,7 @@ this.hasImpulse = true; if (this.getPierceLevel() > 0 && projectiledeflection == ProjectileDeflection.NONE) { -@@ -357,7 +369,7 @@ +@@ -357,7 +381,7 @@ protected void tickDespawn() { ++this.life; if (this.life >= 1200) { @@ -97,7 +116,7 @@ } } -@@ -423,7 +435,7 @@ +@@ -423,7 +447,7 @@ } if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) { @@ -106,7 +125,7 @@ return; } -@@ -444,7 +456,13 @@ +@@ -444,7 +468,13 @@ int k = entity.getRemainingFireTicks(); if (this.isOnFire() && !flag) { @@ -121,7 +140,7 @@ } if (entity.hurtOrSimulate(damagesource, (float) i)) { -@@ -490,7 +508,7 @@ +@@ -490,7 +520,7 @@ this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); if (this.getPierceLevel() <= 0) { @@ -130,7 +149,7 @@ } } else { entity.setRemainingFireTicks(k); -@@ -506,7 +524,7 @@ +@@ -506,7 +536,7 @@ this.spawnAtLocation(worldserver2, this.getPickupItem(), 0.1F); } @@ -139,7 +158,7 @@ } } } -@@ -675,7 +693,7 @@ +@@ -675,7 +705,7 @@ } if (nbt.contains("weapon", 10)) { @@ -148,7 +167,7 @@ } else { this.firedFromWeapon = null; } -@@ -688,34 +706,31 @@ +@@ -688,34 +718,31 @@ Entity entity1 = entity; byte b0 = 0; @@ -195,7 +214,7 @@ } this.pickup = entityarrow_pickupstatus; -@@ -724,9 +739,24 @@ +@@ -724,9 +751,24 @@ @Override public void playerTouch(Player player) { if (!this.level().isClientSide && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) { 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 aa8f8c19cf..70b0990cf3 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 @@ -10,7 +10,37 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { -@@ -152,7 +155,7 @@ +@@ -84,7 +87,29 @@ + this.setOwner(entity); + } + ++ // Spigot Start - copied from tick + @Override ++ public void inactiveTick() { ++ this.life += 1; ++ ++ if (this.life > this.lifetime) { ++ Level world = this.level(); ++ ++ if (world instanceof ServerLevel) { ++ ServerLevel worldserver = (ServerLevel) world; ++ ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(worldserver); ++ } ++ // CraftBukkit end ++ } ++ } ++ super.inactiveTick(); ++ } ++ // Spigot End ++ ++ @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, FireworkRocketEntity.getDefaultItem()); + builder.define(FireworkRocketEntity.DATA_ATTACHED_TO_TARGET, OptionalInt.empty()); +@@ -152,7 +177,7 @@ } if (!this.noPhysics && this.isAlive() && movingobjectposition.getType() != HitResult.Type.MISS) { @@ -19,7 +49,7 @@ this.hasImpulse = true; } -@@ -172,7 +175,11 @@ +@@ -172,7 +197,11 @@ if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; @@ -32,7 +62,7 @@ } } -@@ -182,7 +189,7 @@ +@@ -182,7 +211,7 @@ world.broadcastEntityEvent(this, (byte) 17); this.gameEvent(GameEvent.EXPLODE, this.getOwner()); this.dealExplosionDamage(world); @@ -41,7 +71,7 @@ } @Override -@@ -191,7 +198,11 @@ +@@ -191,7 +220,11 @@ Level world = this.level(); if (world instanceof ServerLevel worldserver) { @@ -54,7 +84,7 @@ } } -@@ -205,7 +216,11 @@ +@@ -205,7 +238,11 @@ if (world instanceof ServerLevel worldserver) { if (this.hasExplosion()) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java index 8b19596e77..b0ffa23faf 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java @@ -39,6 +39,9 @@ public class SpigotTimings { public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); + public static final CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck"); + public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive"); + public static final HashMap entityTypeTimingMap = new HashMap(); public static final HashMap tileEntityTypeTimingMap = new HashMap(); public static final HashMap pluginTaskTimingMap = new HashMap(); diff --git a/paper-server/src/main/java/org/spigotmc/ActivationRange.java b/paper-server/src/main/java/org/spigotmc/ActivationRange.java new file mode 100644 index 0000000000..fb83cadf38 --- /dev/null +++ b/paper-server/src/main/java/org/spigotmc/ActivationRange.java @@ -0,0 +1,263 @@ +package org.spigotmc; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.LightningBolt; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PathfinderMob; +import net.minecraft.world.entity.ambient.AmbientCreature; +import net.minecraft.world.entity.animal.Animal; +import net.minecraft.world.entity.animal.Sheep; +import net.minecraft.world.entity.boss.EnderDragonPart; +import net.minecraft.world.entity.boss.enderdragon.EndCrystal; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.boss.wither.WitherBoss; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.item.PrimedTnt; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.monster.Slime; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; +import net.minecraft.world.entity.projectile.FireworkRocketEntity; +import net.minecraft.world.entity.projectile.ThrowableProjectile; +import net.minecraft.world.entity.projectile.ThrownTrident; +import net.minecraft.world.entity.raid.Raider; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import org.bukkit.craftbukkit.SpigotTimings; + +public class ActivationRange +{ + + public enum ActivationType + { + MONSTER, + ANIMAL, + RAIDER, + MISC; + + AABB boundingBox = new AABB( 0, 0, 0, 0, 0, 0 ); + } + + static AABB maxBB = new AABB( 0, 0, 0, 0, 0, 0 ); + + /** + * Initializes an entities type on construction to specify what group this + * entity is in for activation ranges. + * + * @param entity + * @return group id + */ + public static ActivationType initializeEntityActivationType(Entity entity) + { + if ( entity instanceof Raider ) + { + return ActivationType.RAIDER; + } else if ( entity instanceof Monster || entity instanceof Slime ) + { + return ActivationType.MONSTER; + } else if ( entity instanceof PathfinderMob || entity instanceof AmbientCreature ) + { + return ActivationType.ANIMAL; + } else + { + return ActivationType.MISC; + } + } + + /** + * These entities are excluded from Activation range checks. + * + * @param entity + * @param config + * @return boolean If it should always tick. + */ + public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) + { + if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange == 0 ) + || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0 ) + || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0 ) + || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0 ) + || entity instanceof Player + || entity instanceof ThrowableProjectile + || entity instanceof EnderDragon + || entity instanceof EnderDragonPart + || entity instanceof WitherBoss + || entity instanceof AbstractHurtingProjectile + || entity instanceof LightningBolt + || entity instanceof PrimedTnt + || entity instanceof EndCrystal + || entity instanceof FireworkRocketEntity + || entity instanceof ThrownTrident ) + { + return true; + } + + return false; + } + + /** + * Find what entities are in range of the players in the world and set + * active if in range. + * + * @param world + */ + public static void activateEntities(Level world) + { + SpigotTimings.entityActivationCheckTimer.startTiming(); + final int miscActivationRange = world.spigotConfig.miscActivationRange; + final int raiderActivationRange = world.spigotConfig.raiderActivationRange; + final int animalActivationRange = world.spigotConfig.animalActivationRange; + final int monsterActivationRange = world.spigotConfig.monsterActivationRange; + + int maxRange = Math.max( monsterActivationRange, animalActivationRange ); + maxRange = Math.max( maxRange, raiderActivationRange ); + maxRange = Math.max( maxRange, miscActivationRange ); + maxRange = Math.min( ( world.spigotConfig.simulationDistance << 4 ) - 8, maxRange ); + + for ( Player player : world.players() ) + { + player.activatedTick = MinecraftServer.currentTick; + if ( world.spigotConfig.ignoreSpectatorActivation && player.isSpectator() ) + { + continue; + } + + ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, 256, maxRange ); + ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, 256, miscActivationRange ); + ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange ); + ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, 256, animalActivationRange ); + ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, 256, monsterActivationRange ); + + world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity); + } + SpigotTimings.entityActivationCheckTimer.stopTiming(); + } + + /** + * Checks for the activation state of all entities in this chunk. + * + * @param chunk + */ + private static void activateEntity(Entity entity) + { + if ( MinecraftServer.currentTick > entity.activatedTick ) + { + if ( entity.defaultActivationState ) + { + entity.activatedTick = MinecraftServer.currentTick; + return; + } + if ( entity.activationType.boundingBox.intersects( entity.getBoundingBox() ) ) + { + entity.activatedTick = MinecraftServer.currentTick; + } + } + } + + /** + * If an entity is not in range, do some more checks to see if we should + * give it a shot. + * + * @param entity + * @return + */ + public static boolean checkEntityImmunities(Entity entity) + { + // quick checks. + if ( entity.wasTouchingWater || entity.getRemainingFireTicks() > 0 ) + { + return true; + } + if ( !( entity instanceof AbstractArrow ) ) + { + if ( !entity.onGround() || !entity.passengers.isEmpty() || entity.isPassenger() ) + { + return true; + } + } else if ( !( (AbstractArrow) entity ).isInGround() ) + { + return true; + } + // special cases. + if ( entity instanceof LivingEntity ) + { + LivingEntity living = (LivingEntity) entity; + if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTime > 0 || living.activeEffects.size() > 0 ) + { + return true; + } + if ( entity instanceof PathfinderMob && ( (PathfinderMob) entity ).getTarget() != null ) + { + return true; + } + if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) + { + return true; + } + if ( entity instanceof Animal ) + { + Animal animal = (Animal) entity; + if ( animal.isBaby() || animal.isInLove() ) + { + return true; + } + if ( entity instanceof Sheep && ( (Sheep) entity ).isSheared() ) + { + return true; + } + } + if (entity instanceof Creeper && ((Creeper) entity).isIgnited()) { // isExplosive + return true; + } + } + // SPIGOT-6644: Otherwise the target refresh tick will be missed + if (entity instanceof ExperienceOrb) { + return true; + } + return false; + } + + /** + * Checks if the entity is active for this tick. + * + * @param entity + * @return + */ + public static boolean checkIfActive(Entity entity) + { + SpigotTimings.checkIfActiveTimer.startTiming(); + // Never safe to skip fireworks or item gravity + if (entity instanceof FireworkRocketEntity || (entity instanceof ItemEntity && (entity.tickCount + entity.getId() + 1) % 4 == 0)) { + SpigotTimings.checkIfActiveTimer.stopTiming(); + return true; + } + + boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState; + + // Should this entity tick? + if ( !isActive ) + { + if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 ) + { + // Check immunities every 20 ticks. + if ( ActivationRange.checkEntityImmunities( entity ) ) + { + // Triggered some sort of immunity, give 20 full ticks before we check again. + entity.activatedTick = MinecraftServer.currentTick + 20; + } + isActive = true; + } + // Add a little performance juice to active entities. Skip 1/4 if not immune. + } else if ( !entity.defaultActivationState && entity.tickCount % 4 == 0 && !ActivationRange.checkEntityImmunities( entity ) ) + { + isActive = false; + } + SpigotTimings.checkIfActiveTimer.stopTiming(); + return isActive; + } +} diff --git a/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java b/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java index 7d1d2a4d32..da22dbeaad 100644 --- a/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/paper-server/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -194,4 +194,21 @@ public class SpigotWorldConfig this.itemDespawnRate = this.getInt( "item-despawn-rate", 6000 ); this.log( "Item Despawn Rate: " + this.itemDespawnRate ); } + + public int animalActivationRange = 32; + public int monsterActivationRange = 32; + public int raiderActivationRange = 48; + public int miscActivationRange = 16; + public boolean tickInactiveVillagers = true; + public boolean ignoreSpectatorActivation = false; + private void activationRange() + { + this.animalActivationRange = this.getInt( "entity-activation-range.animals", this.animalActivationRange ); + this.monsterActivationRange = this.getInt( "entity-activation-range.monsters", this.monsterActivationRange ); + this.raiderActivationRange = this.getInt( "entity-activation-range.raiders", this.raiderActivationRange ); + this.miscActivationRange = this.getInt( "entity-activation-range.misc", this.miscActivationRange ); + this.tickInactiveVillagers = this.getBoolean( "entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers ); + this.ignoreSpectatorActivation = this.getBoolean( "entity-activation-range.ignore-spectators", this.ignoreSpectatorActivation ); + this.log( "Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers + " / Isa " + this.ignoreSpectatorActivation ); + } }