public void setMobLimit(final int initialLimit, final int addPerPlayer, final int largestLimit) {
   this.mobLimit =
       world ->
           Math.min(
               largestLimit,
               initialLimit + EntitySelector.players(world, area.toAABB()).size() * addPerPlayer);
 }
  @Override
  public void tick(World world, NBTCompound nbt) {
    if (++tickLimiter > tickRate) {
      tickLimiter = 0;

      List<EntityLiving> mobs = EntitySelector.mobs(world, area.toAABB());
      if (mobs.size() >= mobLimit.applyAsInt(world)) return;

      final Map<Class<? extends EntityLiving>, Integer> mobCounts = new HashMap<>(4);
      final boolean isPeaceful = world.difficultySetting == EnumDifficulty.PEACEFUL;

      for (int attempt = 0; attempt < attemptsPerTick; attempt++) {
        final SpawnEntry<? extends EntityLiving> entry = spawnEntries.getRandomItem(world.rand);
        final Class<? extends EntityLiving> mobClass = entry.getMobClass();

        if (!isPeaceful || !entry.isHostile) {
          int limit = mobClassLimit.get(mobClass);

          if (limit == 0
              || mobCounts.computeIfAbsent(
                      mobClass,
                      cls ->
                          (int)
                              mobs.stream().filter(entity -> entity.getClass() == mobClass).count())
                  < limit) {
            entry.trySpawn(world, attemptsPerMob);
          }
        }
      }
    }
  }
 /**
  * Checks whether the area between two points is inside the structure and does not intersect any
  * existing pieces.
  */
 protected boolean canPlaceArea(Pos pos1, Pos pos2) {
   final BoundingBox box = new BoundingBox(pos1, pos2);
   return box.isInside(dungeon.boundingBox)
       && !generated.stream().anyMatch(inst -> inst.boundingBox.intersects(box));
 }