--- a/net/minecraft/world/level/BaseSpawner.java +++ b/net/minecraft/world/level/BaseSpawner.java @@ -49,15 +49,17 @@ public int maxNearbyEntities = 6; public int requiredPlayerRange = 16; public int spawnRange = 4; + private int tickDelay = 0; // Paper - Configurable mob spawner tick rate public BaseSpawner() {} public void setEntityId(EntityType type, @Nullable Level world, RandomSource random, BlockPos pos) { this.getOrCreateNextSpawnData(world, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString()); + this.spawnPotentials = SimpleWeightedRandomList.empty(); // CraftBukkit - SPIGOT-3496, MC-92282 } public boolean isNearPlayer(Level world, BlockPos pos) { - return world.hasNearbyAlivePlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); + return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API } public void clientTick(Level world, BlockPos pos) { @@ -82,13 +84,19 @@ } public void serverTick(ServerLevel world, BlockPos pos) { + if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick + // Paper start - Configurable mob spawner tick rate + if (spawnDelay > 0 && --tickDelay > 0) return; + tickDelay = world.paperConfig().tickRates.mobSpawner; + if (tickDelay == -1) { return; } // If disabled + // Paper end - Configurable mob spawner tick rate if (this.isNearPlayer(world, pos)) { - if (this.spawnDelay == -1) { + if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate this.delay(world, pos); } if (this.spawnDelay > 0) { - --this.spawnDelay; + this.spawnDelay -= tickDelay; // Paper - Configurable mob spawner tick rate } else { boolean flag = false; RandomSource randomsource = world.getRandom(); @@ -125,6 +133,20 @@ } else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, EntitySpawnReason.SPAWNER, blockposition1, world.getRandom())) { continue; } + // Paper start - PreCreatureSpawnEvent + com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent( + io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), + org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()), + io.papermc.paper.util.MCUtil.toLocation(world, pos) + ); + if (!event.callEvent()) { + flag = true; + if (event.shouldAbortSpawn()) { + break; + } + continue; + } + // Paper end - PreCreatureSpawnEvent Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, EntitySpawnReason.SPAWNER, (entity1) -> { entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); @@ -143,6 +165,7 @@ return; } + entity.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; preserve entity motion from tag entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F); if (entity instanceof Mob) { Mob entityinsentient = (Mob) entity; @@ -157,13 +180,27 @@ ((Mob) entity).finalizeSpawn(world, world.getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.SPAWNER, (SpawnGroupData) null); } - Optional optional1 = mobspawnerdata.getEquipment(); + Optional optional1 = mobspawnerdata.getEquipment(); // CraftBukkit - decompile error Objects.requireNonNull(entityinsentient); optional1.ifPresent(entityinsentient::equip); + // Spigot Start + if ( entityinsentient.level().spigotConfig.nerfSpawnerMobs ) + { + entityinsentient.aware = false; + } + // Spigot End } - if (!world.tryAddFreshEntityWithPassengers(entity)) { + entity.spawnedViaMobSpawner = true; // Paper + entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason + flag = true; // Paper + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) { + continue; + } + if (!world.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER)) { + // CraftBukkit end this.delay(world, pos); return; } @@ -174,7 +211,7 @@ ((Mob) entity).spawnAnim(); } - flag = true; + //flag = true; // Paper - moved up above cancellable event } } @@ -202,7 +239,13 @@ } public void load(@Nullable Level world, BlockPos pos, CompoundTag nbt) { + // Paper start - use larger int if set + if (nbt.contains("Paper.Delay")) { + this.spawnDelay = nbt.getInt("Paper.Delay"); + } else { this.spawnDelay = nbt.getShort("Delay"); + } + // Paper end boolean flag = nbt.contains("SpawnData", 10); if (flag) { @@ -225,9 +268,15 @@ this.spawnPotentials = SimpleWeightedRandomList.single(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData()); } + // Paper start - use ints if set + if (nbt.contains("Paper.MinSpawnDelay", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { + this.minSpawnDelay = nbt.getInt("Paper.MinSpawnDelay"); + this.maxSpawnDelay = nbt.getInt("Paper.MaxSpawnDelay"); + this.spawnCount = nbt.getShort("SpawnCount"); + } else // Paper end if (nbt.contains("MinSpawnDelay", 99)) { - this.minSpawnDelay = nbt.getShort("MinSpawnDelay"); - this.maxSpawnDelay = nbt.getShort("MaxSpawnDelay"); + this.minSpawnDelay = nbt.getInt("MinSpawnDelay"); // Paper - short -> int + this.maxSpawnDelay = nbt.getInt("MaxSpawnDelay"); // Paper - short -> int this.spawnCount = nbt.getShort("SpawnCount"); } @@ -244,9 +293,20 @@ } public CompoundTag save(CompoundTag nbt) { - nbt.putShort("Delay", (short) this.spawnDelay); - nbt.putShort("MinSpawnDelay", (short) this.minSpawnDelay); - nbt.putShort("MaxSpawnDelay", (short) this.maxSpawnDelay); + // Paper start + if (spawnDelay > Short.MAX_VALUE) { + nbt.putInt("Paper.Delay", this.spawnDelay); + } + nbt.putShort("Delay", (short) Math.min(Short.MAX_VALUE, this.spawnDelay)); + + if (minSpawnDelay > Short.MAX_VALUE || maxSpawnDelay > Short.MAX_VALUE) { + nbt.putInt("Paper.MinSpawnDelay", this.minSpawnDelay); + nbt.putInt("Paper.MaxSpawnDelay", this.maxSpawnDelay); + } + + nbt.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay)); + nbt.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay)); + // Paper end nbt.putShort("SpawnCount", (short) this.spawnCount); nbt.putShort("MaxNearbyEntities", (short) this.maxNearbyEntities); nbt.putShort("RequiredPlayerRange", (short) this.requiredPlayerRange);