package joshie.harvest.calendar.provider;
import joshie.harvest.api.HFApi;
import joshie.harvest.api.calendar.Season;
import joshie.harvest.api.calendar.Weather;
import joshie.harvest.calendar.SnowLoader;
import joshie.harvest.calendar.data.Calendar;
import joshie.harvest.calendar.render.WeatherRenderer;
import joshie.harvest.core.HFTrackers;
import joshie.harvest.core.helpers.MCClientHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.World;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.client.IRenderHandler;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
import static joshie.harvest.calendar.HFCalendar.TICKS_PER_DAY;
public class HFWorldProvider extends WorldProviderSurface {
@SideOnly(Side.CLIENT)
private IRenderHandler WEATHER_RENDERER;
@SideOnly(Side.CLIENT)
@Override
@Nonnull
public IRenderHandler getWeatherRenderer() {
if (WEATHER_RENDERER != null) return WEATHER_RENDERER;
else WEATHER_RENDERER = new WeatherRenderer();
return WEATHER_RENDERER;
}
@SideOnly(Side.CLIENT)
@Override
public float getStarBrightness(float f) {
float brightness = super.getStarBrightness(f);
return HFTrackers.getCalendar(MCClientHelper.getWorld()).getDate().getSeason() == Season.WINTER ? brightness * 1.25F : brightness;
}
@SideOnly(Side.CLIENT)
@Override
public float getSunBrightness(float f) {
float brightness = worldObj.getSunBrightnessBody(f);
return HFTrackers.getCalendar(MCClientHelper.getWorld()).getDate().getSeason() == Season.SUMMER ? brightness * 1.25F : brightness;
}
private static int skyX, skyZ;
private static boolean skyInit;
private static int skyRGBMultiplier;
public static void reset() {
skyX = 0;
skyZ = 0;
skyRGBMultiplier = 0;
skyInit = false;
}
private int getSkyBlendColour(World world, BlockPos center) {
if (center.getX() == skyX && center.getZ() == skyZ && skyInit) {
return skyRGBMultiplier;
}
skyInit = true;
GameSettings settings = Minecraft.getMinecraft().gameSettings;
int[] ranges = ForgeModContainer.blendRanges;
int distance = 0;
if (settings.fancyGraphics && settings.renderDistanceChunks >= 0 && settings.renderDistanceChunks < ranges.length) {
distance = ranges[settings.renderDistanceChunks];
}
int original = HFTrackers.getCalendar(MCClientHelper.getWorld()).getSeasonData().skyColor;
int r = (original & 0xFF0000) >> 16;
int g = (original & 0x00FF00) >> 8;
int b = original & 0x0000FF;
r += (original & 0xFF0000) >> 16;
g += (original & 0x00FF00) >> 8;
b += original & 0x0000FF;
int divider = 2;
for (int x = -distance; x <= distance; ++x) {
for (int z = -distance; z <= distance; ++z) {
BlockPos pos = center.add(x, 0, z);
Biome biome = world.getBiome(pos);
int colour = biome.getSkyColorByTemp(biome.getFloatTemperature(pos));
r += (colour & 0xFF0000) >> 16;
g += (colour & 0x00FF00) >> 8;
b += colour & 0x0000FF;
r += (original & 0xFF0000) >> 16;
g += (original & 0x00FF00) >> 8;
b += original & 0x0000FF;
divider+= 2;
}
}
int multiplier = (r / divider & 255) << 16 | (g / divider & 255) << 8 | b / divider & 255;
skyX = center.getX();
skyZ = center.getY();
skyRGBMultiplier = multiplier;
return skyRGBMultiplier;
}
@SideOnly(Side.CLIENT)
@Override
@Nonnull
public Vec3d getSkyColor(@Nonnull Entity cameraEntity, float partialTicks) {
float f1 = worldObj.getCelestialAngle(partialTicks);
float f2 = MathHelper.cos(f1 * (float) Math.PI * 2.0F) * 2.0F + 0.5F;
if (f2 < 0.0F) {
f2 = 0.0F;
}
if (f2 > 1.0F) {
f2 = 1.0F;
}
int l = getSkyBlendColour(worldObj, new BlockPos(cameraEntity));
float f4 = (float) (l >> 16 & 255) / 255.0F;
float f5 = (float) (l >> 8 & 255) / 255.0F;
float f6 = (float) (l & 255) / 255.0F;
f4 *= f2;
f5 *= f2;
f6 *= f2;
float f7 = Math.min(1F, worldObj.getRainStrength(partialTicks));
float f8;
float f9;
if (f7 > 0.0F) {
f8 = (f4 * 0.3F + f5 * 0.59F + f6 * 0.11F) * 0.6F;
f9 = 1.0F - f7 * 0.75F;
f4 = f4 * f9 + f8 * (1.0F - f9);
f5 = f5 * f9 + f8 * (1.0F - f9);
f6 = f6 * f9 + f8 * (1.0F - f9);
}
f8 = worldObj.getThunderStrength(partialTicks);
if (f8 > 0.0F) {
f8 /= 10F;
f9 = (f4 * 0.3F + f5 * 0.59F + f6 * 0.11F) * 0.2F;
float f10 = 1.0F - f8 * 0.75F;
f4 = f4 * f10 + f9 * (1.0F - f10);
f5 = f5 * f10 + f9 * (1.0F - f10);
f6 = f6 * f10 + f9 * (1.0F - f10);
}
if (worldObj.getLastLightningBolt() > 0) {
f9 = (float) worldObj.getLastLightningBolt() - partialTicks;
if (f9 > 1.0F) {
f9 = 1.0F;
}
f9 *= 0.45F;
f4 = f4 * (1.0F - f9) + 0.8F * f9;
f5 = f5 * (1.0F - f9) + 0.8F * f9;
f6 = f6 * (1.0F - f9) + 1.0F * f9;
}
return new Vec3d((double) f4, (double) f5, (double) f6);
}
@Override
public float calculateCelestialAngle(long worldTime, float partialTicks) {
Calendar calendar = HFTrackers.getCalendar(worldObj);
if (calendar != null) {
return calendar.getSeasonData().getCelestialAngle(worldTime % TICKS_PER_DAY);
}
return 1F;
}
@Override
public boolean isBlockHighHumidity(@Nonnull BlockPos pos) {
return HFApi.calendar.getDate(worldObj).getSeason() != Season.SUMMER && super.isBlockHighHumidity(pos);
}
private boolean isWater(BlockPos pos) {
return worldObj.getBlockState(pos).getMaterial() == Material.WATER;
}
@Override
public boolean canBlockFreeze(@Nonnull BlockPos pos, boolean byWater) {
Biome biome = worldObj.getBiome(pos);
if (!biome.canRain() || biome.isHighHumidity()) {
return super.canBlockFreeze(pos, byWater);
} else if (biome.isSnowyBiome()) {
Weather weather = HFApi.calendar.getWeather(worldObj);
return !weather.isRain() && super.canBlockFreeze(pos, byWater);
} else {
Weather weather = HFApi.calendar.getWeather(worldObj);
float f = biome.getFloatTemperature(pos);
if (weather.isSnow() && f > 0.15F) {
if (pos.getY() >= 0 && pos.getY() < 256 && worldObj.getLightFor(EnumSkyBlock.BLOCK, pos) < 10) {
IBlockState iblockstate = worldObj.getBlockState(pos);
Block block = iblockstate.getBlock();
if ((block == Blocks.WATER || block == Blocks.FLOWING_WATER) && iblockstate.getValue(BlockLiquid.LEVEL) == 0) {
if (!byWater) {
HFApi.tickable.addTickable(worldObj, pos, SnowLoader.INSTANCE);
return true;
}
boolean flag = isWater(pos.west()) && isWater(pos.east()) && isWater(pos.north()) && isWater(pos.south());
if (!flag) {
HFApi.tickable.addTickable(worldObj, pos, SnowLoader.INSTANCE);
return true;
}
}
}
return false;
} else return super.canBlockFreeze(pos, byWater);
}
}
@Override
public boolean canSnowAt(@Nonnull BlockPos pos, boolean checkLight) {
Biome biome = worldObj.getBiome(pos);
if (!biome.canRain() || biome.isHighHumidity()) {
return super.canSnowAt(pos, checkLight);
} else if (biome.isSnowyBiome()) {
Weather weather = HFApi.calendar.getWeather(worldObj);
return !weather.isRain() && super.canSnowAt(pos, checkLight);
} else {
Weather weather = HFApi.calendar.getWeather(worldObj);
float f = biome.getFloatTemperature(pos);
if (weather.isSnow() && f > 0.15F) {
if (!checkLight) {
return true;
} else {
if (pos.getY() >= 0 && pos.getY() < 256 && worldObj.getLightFor(EnumSkyBlock.BLOCK, pos) < 10) {
IBlockState iblockstate = worldObj.getBlockState(pos);
if (iblockstate.getBlock() != Blocks.SNOW_LAYER && iblockstate.getBlock().isReplaceable(worldObj, pos) && Blocks.SNOW_LAYER.canPlaceBlockAt(worldObj, pos)) {
HFApi.tickable.addTickable(worldObj, pos, SnowLoader.INSTANCE);
return true;
}
}
return false;
}
} else return super.canSnowAt(pos, checkLight);
}
}
@Override
public void updateWeather() {
Calendar calendar = HFTrackers.getCalendar(worldObj);
int targetRain = calendar.getTodaysRainStrength();
int targetStorm = calendar.getTodaysStormStrength();
int rainStrength = (int) (worldObj.rainingStrength * 100);
if (rainStrength > targetRain) {
worldObj.rainingStrength -= 0.01F;
} else if (rainStrength < targetRain) {
worldObj.rainingStrength += 0.01F;
}
int thunderStrength = (int) (worldObj.thunderingStrength * 100);
if (thunderStrength > targetStorm) {
worldObj.thunderingStrength -= 0.1F;
} else if (thunderStrength < targetStorm) {
worldObj.thunderingStrength += 0.01F;
}
}
}