/**
  * Gets if rain is falling nearby the block specified
  *
  * @param block to check it nearby of
  * @return True if it is raining, False if not
  */
 public static boolean hasRainNearby(Block block) {
   Sky sky = block.getWorld().get(Sky.class);
   if (sky != null && sky.hasWeather()) {
     if (sky.getWeatherSimulator().isRainingAt(block.getX(), block.getY(), block.getZ(), false)) {
       for (BlockFace face : BlockFaces.NESW) {
         if (block.translate(face).isAtSurface()) {
           return true;
         }
       }
     }
   }
   return false;
 }
 @Override
 public void onTick(float dt) {
   final Random random = GenericMath.getRandom();
   float secondsUntilWeatherChange = sky.getData().get(VanillaData.WEATHER_CHANGE_TIME);
   secondsUntilWeatherChange -= dt;
   if (forceWeatherUpdate.compareAndSet(true, false) || secondsUntilWeatherChange <= 0) {
     this.sky.updateWeather(getCurrent(), getForecast());
     sky.getData().put(VanillaData.WORLD_WEATHER, getForecast());
     final Weather current = getCurrent();
     Weather forecast = current;
     while (forecast == current) {
       // When Rain/Snow or Thunderstorms occur, always go to Clear after.
       if (current == Weather.RAIN || current == Weather.THUNDERSTORM) {
         forecast = Weather.CLEAR;
       } else {
         forecast = Weather.get(random.nextInt(3));
       }
       setForecast(forecast);
     }
     setForecast(forecast);
     secondsUntilWeatherChange =
         current.getBaseWeatherTime() + random.nextInt(current.getRandomWeatherTime());
     if (VanillaPlugin.getInstance().getEngine().debugMode()) {
       Spout.getLogger()
           .info(
               "Weather changed to: "
                   + current
                   + ", next change in "
                   + secondsUntilWeatherChange / 1000F
                   + "s");
     }
   }
   float currentRainStrength = sky.getData().get(VanillaData.CURRENT_RAIN_STRENGTH);
   sky.getData().put(VanillaData.PREVIOUS_RAIN_STRENGTH, currentRainStrength);
   if (this.isRaining()) {
     currentRainStrength = Math.min(1.0f, currentRainStrength + 0.01f);
   } else {
     currentRainStrength = Math.max(0.0f, currentRainStrength - 0.01f);
   }
   sky.getData().put(VanillaData.CURRENT_RAIN_STRENGTH, currentRainStrength);
   if (hasLightning()) {
     lightning.onTick(dt);
   }
   if (getCurrent().isRaining()) {
     snowfall.onTick(dt);
   }
   sky.getData().put(VanillaData.WEATHER_CHANGE_TIME, secondsUntilWeatherChange);
 }
 public void setForecast(Weather weather) {
   sky.getData().put(VanillaData.WORLD_FORECAST, weather);
 }
 public Weather getForecast() {
   return sky.getData().get(VanillaData.WORLD_FORECAST);
 }
 public Weather getCurrent() {
   return sky.getData().get(VanillaData.WORLD_WEATHER);
 }
 public World getWorld() {
   return sky.getOwner();
 }
 /**
  * Gets the strength of the rain, which is affected by the duration
  *
  * @param factor to apply to the changing states
  * @return the strength
  */
 public float getRainStrength(float factor) {
   final float prevRainStr = sky.getData().get(VanillaData.PREVIOUS_RAIN_STRENGTH);
   return (prevRainStr
       + factor * (sky.getData().get(VanillaData.CURRENT_RAIN_STRENGTH) - prevRainStr));
 }