Entity Activation Range

This feature gives 3 new configurable ranges that if an entity of the matching type is outside of this radius of any player, will tick at 5% of its normal rate.

This will drastically cut down on tick timings for entities that are not in range of a user to actually be "used".
This change can have dramatic impact on gameplay if configured too low. Balance according to your servers desired gameplay.

By: Aikar <aikar@aikar.co>
This commit is contained in:
CraftBukkit/Spigot 2024-11-02 18:16:11 +11:00
parent 54a84c6c79
commit 28c8009a16
12 changed files with 730 additions and 262 deletions

View file

@ -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> 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<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
@ -657,7 +665,7 @@
}
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
@@ -1226,17 +1429,24 @@
@@ -1226,17 +1437,24 @@
}
public <T extends ParticleOptions> 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<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
@ -694,7 +702,7 @@
return null;
} else {
Optional<HolderSet.Named<Structure>> 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 <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
try {
Object2IntOpenHashMap<String> 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<Entity> 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);

View file

@ -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<? extends AgeableMob> 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();

View file

@ -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);

View file

@ -96,7 +96,7 @@
private static final EntityDataAccessor<Integer> 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<Entity.Movement> movementThisTick;
private final Set<BlockState> 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<Relative> 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<Relative> 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() {

View file

@ -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<EquipmentSlot, Reference2ObjectMap<Enchantment, Set<EnchantmentLocationBasedEffect>>> 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<? extends LivingEntity> 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<MobEffect> 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<BlockPos> 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<ItemStack> 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<ItemStack> 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<EquipmentSlot, ItemStack> 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);

View file

@ -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();

View file

@ -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();

View file

@ -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<? extends AbstractArrow> type, Level world) {
super(type, world);
this.pickup = AbstractArrow.Pickup.DISALLOWED;
@@ -88,23 +105,30 @@
}
protected AbstractArrow(EntityType<? extends AbstractArrow> 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<? extends AbstractArrow> 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<? extends AbstractArrow> 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) {

View file

@ -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()) {

View file

@ -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<String, CustomTimingsHandler> entityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
public static final HashMap<String, CustomTimingsHandler> tileEntityTypeTimingMap = new HashMap<String, CustomTimingsHandler>();
public static final HashMap<String, CustomTimingsHandler> pluginTaskTimingMap = new HashMap<String, CustomTimingsHandler>();

View file

@ -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;
}
}

View file

@ -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 );
}
}