public class TealMeteorEntity extends FallingBlockEntity {

    @Override

    public void tick() {

        super.tick();

        // Smoke trail

        level().addParticle(

                ParticleTypes.SOUL_FIRE_FLAME,

                getX(),

                getY(),

                getZ(),

                0,

                -0.1,

                0

        );

        // Impact

        if (this.onGround()) {

            BlockPos center = this.blockPosition();

            // Small explosion (doesn't destroy everything)

            level().explode(

                    this,

                    center.getX(),

                    center.getY(),

                    center.getZ(),

                    4.0F,

                    Level.ExplosionInteraction.NONE

            );

            // Create infection crater

            createCrystalCrater(center);

            discard();

        }

    }

}

private void createCrystalCrater(BlockPos center) {

    int radius = 8;

    for (int x = -radius; x <= radius; x++) {

        for (int y = -3; y <= 2; y++) {

            for (int z = -radius; z <= radius; z++) {

                BlockPos pos = center.offset(x, y, z);

                double distance = Math.sqrt(x*x + y*y + z*z);

                if(distance <= radius) {

                    if(level().getRandom().nextFloat() < 0.7F){

                        level().setBlock(

                                pos,

                                ModBlocks.TEAL_CRYSTAL_BLOCK.get().defaultBlockState(),

                                3

                        );

                    }

                }

            }

        }

    }

}

AABB area = new AABB(center).inflate(20);

for(LivingEntity entity :

        level().getEntitiesOfClass(LivingEntity.class, area)){

    entity.addEffect(new MobEffectInstance(

            ModEffects.TEAL_INFECTION.get(),

            1200,

            0

    ));

}

@SubscribeEvent

public static void worldTick(LevelTickEvent.Post event){

    Level level = event.getLevel();

    if(level.getRandom().nextInt(24000) == 0){

        BlockPos spawn = new BlockPos(

                level.getRandom().nextInt(5000) - 2500,

                250,

                level.getRandom().nextInt(5000) - 2500

        );

        TealMeteorEntity meteor =

                new TealMeteorEntity(level);

        meteor.setPos(

                spawn.getX(),

                spawn.getY(),

                spawn.getZ()

        );

        level.addFreshEntity(meteor);

    }

}

public class MeteorManager {

    // Total meteors that will ever fall

    public static final int MAX_METEORS =

            5 + new Random().nextInt(6); // 5-10

    public static int meteorsSpawned = 0;

    public static boolean canSpawnMeteor() {

        return meteorsSpawned < MAX_METEORS;

    }

    public static void meteorSpawned() {

        meteorsSpawned++;

    }

}

@SubscribeEvent

public static void onWorldTick(LevelTickEvent.Post event) {

    Level level = event.getLevel();

    // Stop if we've reached the limit

    if (!MeteorManager.canSpawnMeteor()) {

        return;

    }

    // Random chance every tick

    if (level.getRandom().nextInt(24000) == 0) {

        BlockPos spawnPos = new BlockPos(

                level.getRandom().nextInt(5000) - 2500,

                250,

                level.getRandom().nextInt(5000) - 2500

        );

        TealMeteorEntity meteor = new TealMeteorEntity(level);

        meteor.setPos(spawnPos.getX(), spawnPos.getY(), spawnPos.getZ());

        level.addFreshEntity(meteor);

        MeteorManager.meteorSpawned();

        System.out.println(

                "Meteor " +

                MeteorManager.meteorsSpawned +

                " of " +

                MeteorManager.MAX_METEORS

        );

    }

}

if (MeteorManager.meteorsSpawned >= MeteorManager.MAX_METEORS) {

    for (ServerPlayer player : server.getPlayerList().getPlayers()) {

        player.sendSystemMessage(Component.literal(

            "§bThe final Teal Crystal Meteor has fallen. The infection has begun..."

        ));

    }

    // Start global infection phase here.

}

for (ServerPlayer player : server.getPlayerList().getPlayers()) {

    player.sendSystemMessage(Component.literal(

        "§3A Teal Crystal Meteor has crashed! (" +

        MeteorManager.meteorsSpawned +

        "/" +

        MeteorManager.MAX_METEORS +

        ")"

    ));

}