def bounded_stats_per_chunk(chunk, block_counts, start, stop):
    """Given a chunk, return the number of blocks types within the specified selection"""
    chunk_z, chunk_x = chunk.get_coords()
    for z in range(16):
        world_z = z + chunk_z*16
        if ( (start != None and world_z < int(start[2])) or (stop != None and  world_z > int(stop[2])) ):
            # Outside the bounding box; skip to next iteration
            #print("Z break: %d,%d,%d" % (world_z,start[2],stop[2]))
            break
        for x in range(16):
            world_x = x + chunk_x*16
            if ( (start != None and world_x < int(start[0])) or (stop != None and world_x > int(stop[0])) ):
                # Outside the bounding box; skip to next iteration
                #print("X break: %d,%d,%d" % (world_x,start[0],stop[0]))
                break
            for y in range(chunk.get_max_height() + 1):
                if ( (start != None and y < int(start[1])) or (stop != None and y > int(stop[1])) ):
                    # Outside the bounding box; skip to next iteration
                    #print("Y break: %d,%d,%d" % (y,start[1],stop[1]))
                    break
                
                #print("Chunk: %d,%d Coord: %d,%d,%d" % (c['x'], c['z'],x,y,z))
                block_id = chunk.get_block(x,y,z)
                if block_id != None:
                    try:
                        block_counts[block_id] += 1
                    except KeyError:
                        block_counts[block_id] = 1
Given a chunk, return the number of blocks types within the specified selection