package mcjty.rftools.dimension.world;
import cpw.mods.fml.common.Optional;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import ivorius.reccomplex.dimensions.DimensionDictionary;
import mcjty.lib.varia.Logging;
import mcjty.rftools.api.dimension.RFToolsWorldProvider;
import mcjty.rftools.blocks.dimlets.DimletConfiguration;
import mcjty.rftools.dimension.DimensionInformation;
import mcjty.rftools.dimension.DimensionStorage;
import mcjty.rftools.dimension.RfToolsDimensionManager;
import mcjty.rftools.dimension.description.WeatherDescriptor;
import mcjty.rftools.dimension.network.PacketGetDimensionEnergy;
import mcjty.rftools.dimension.world.types.ControllerType;
import mcjty.rftools.dimension.world.types.SkyType;
import mcjty.rftools.dimension.world.types.StructureType;
import mcjty.rftools.items.dimlets.types.Patreons;
import mcjty.rftools.network.RFToolsMessages;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.Vec3;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.biome.WorldChunkManager;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraftforge.common.DimensionManager;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@Optional.InterfaceList(@Optional.Interface(iface = "ivorius.reccomplex.dimensions.DimensionDictionary$Handler", modid = "reccomplex"))
public class GenericWorldProvider extends WorldProvider implements DimensionDictionary.Handler, RFToolsWorldProvider {
public static final String RFTOOLS_DIMENSION = "rftools dimension";
private DimensionInformation dimensionInformation;
private DimensionStorage storage;
private long seed;
private Set<String> dimensionTypes = null; // Used for Recurrent Complex support
private long calculateSeed(long seed, int dim) {
return dim * 13L + seed;
}
@Override
public long getSeed() {
if (dimensionInformation == null || dimensionInformation.getWorldVersion() < DimensionInformation.VERSION_CORRECTSEED) {
return super.getSeed();
} else {
return seed;
}
}
private DimensionInformation getDimensionInformation() {
if (dimensionInformation == null) {
int dim = worldObj.provider.dimensionId;
dimensionInformation = RfToolsDimensionManager.getDimensionManager(worldObj).getDimensionInformation(dim);
if (dimensionInformation == null) {
Logging.log("Dimension information for dimension " + dim + " is missing!");
} else {
setSeed(dim);
setupProviderInfo();
}
}
return dimensionInformation;
}
@Override
@Optional.Method(modid = "reccomplex")
public Set<String> getDimensionTypes() {
getDimensionInformation();
if (dimensionInformation == null) {
return Collections.EMPTY_SET;
}
if (dimensionTypes == null) {
dimensionTypes = new HashSet<String>();
dimensionTypes.add(DimensionDictionary.INFINITE);
dimensionTypes.add("RFTOOLS_DIMENSION");
// @todo temporary. This should probably be in the TerrainType enum.
switch (dimensionInformation.getTerrainType()) {
case TERRAIN_VOID:
case TERRAIN_ISLAND:
case TERRAIN_ISLANDS:
case TERRAIN_CHAOTIC:
case TERRAIN_PLATEAUS:
case TERRAIN_GRID:
dimensionTypes.add(DimensionDictionary.NO_TOP_LIMIT);
dimensionTypes.add(DimensionDictionary.NO_BOTTOM_LIMIT);
break;
case TERRAIN_FLAT:
case TERRAIN_AMPLIFIED:
case TERRAIN_NORMAL:
case TERRAIN_NEARLANDS:
dimensionTypes.add(DimensionDictionary.NO_TOP_LIMIT);
dimensionTypes.add(DimensionDictionary.BOTTOM_LIMIT);
break;
case TERRAIN_CAVERN_OLD:
dimensionTypes.add(DimensionDictionary.BOTTOM_LIMIT);
dimensionTypes.add(DimensionDictionary.TOP_LIMIT);
break;
case TERRAIN_CAVERN:
case TERRAIN_LOW_CAVERN:
case TERRAIN_FLOODED_CAVERN:
dimensionTypes.add(DimensionDictionary.BOTTOM_LIMIT);
dimensionTypes.add(DimensionDictionary.NO_TOP_LIMIT);
break;
}
if (dimensionInformation.hasStructureType(StructureType.STRUCTURE_RECURRENTCOMPLEX)) {
Collections.addAll(dimensionTypes, dimensionInformation.getDimensionTypes());
}
}
return dimensionTypes;
}
private void setSeed(int dim) {
if (dimensionInformation == null) {
if (worldObj == null) {
return;
}
dimensionInformation = RfToolsDimensionManager.getDimensionManager(worldObj).getDimensionInformation(dim);
if (dimensionInformation == null) {
Logging.log("Error: setSeed() called with null diminfo. Error ignored!");
return;
}
}
long forcedSeed = dimensionInformation.getForcedDimensionSeed();
if (forcedSeed != 0) {
Logging.log("Forced seed for dimension " + dim + ": " + forcedSeed);
seed = forcedSeed;
} else {
long baseSeed = dimensionInformation.getBaseSeed();
if (baseSeed != 0) {
seed = calculateSeed(baseSeed, dim) ;
} else {
seed = calculateSeed(worldObj.getSeed(), dim) ;
}
}
}
@Override
public void registerWorldChunkManager() {
getDimensionInformation();
storage = DimensionStorage.getDimensionStorage(worldObj);
setupProviderInfo();
}
private void setupProviderInfo() {
if (dimensionInformation != null) {
ControllerType type = dimensionInformation.getControllerType();
if (type == ControllerType.CONTROLLER_SINGLE) {
worldChunkMgr = new SingleBiomeWorldChunkManager(worldObj, worldObj.getSeed(), terrainType);
} else if (type == ControllerType.CONTROLLER_DEFAULT) {
worldChunkMgr = new WorldChunkManager(seed, worldObj.getWorldInfo().getTerrainType());
} else {
GenericWorldChunkManager.hackyDimensionInformation = dimensionInformation; // Hack to get the dimension information in the superclass.
worldChunkMgr = new GenericWorldChunkManager(seed, worldObj.getWorldInfo().getTerrainType(), dimensionInformation);
}
} else {
worldChunkMgr = new WorldChunkManager(seed, worldObj.getWorldInfo().getTerrainType());
}
if (dimensionInformation != null) {
hasNoSky = !dimensionInformation.getTerrainType().hasSky();
if (worldObj.isRemote) {
// Only on client!
SkyType skyType = dimensionInformation.getSkyDescriptor().getSkyType();
if (hasNoSky) {
SkyRenderer.registerNoSky(this);
} else if (skyType == SkyType.SKY_ENDER) {
SkyRenderer.registerEnderSky(this);
} else if (skyType == SkyType.SKY_INFERNO || skyType == SkyType.SKY_STARS1 || skyType == SkyType.SKY_STARS2 || skyType == SkyType.SKY_STARS3) {
SkyRenderer.registerSkybox(this, skyType);
} else {
SkyRenderer.registerSky(this, dimensionInformation);
}
if (dimensionInformation.getSkyDescriptor().isCloudColorGiven() || dimensionInformation.isPatreonBitSet(Patreons.PATREON_KENNEY)) {
SkyRenderer.registerCloudRenderer(this, dimensionInformation);
}
}
}
}
public static WorldProvider getProviderForDimension(int id) {
return DimensionManager.createProviderFor(id);
}
@Override
public double getHorizon() {
getDimensionInformation();
if (dimensionInformation != null && dimensionInformation.getTerrainType().hasNoHorizon()) {
return 0;
} else {
return super.getHorizon();
}
}
@Override
public boolean isSurfaceWorld() {
getDimensionInformation();
if (dimensionInformation == null) {
return super.isSurfaceWorld();
}
return dimensionInformation.getTerrainType().hasSky();
}
@Override
public String getDimensionName() {
return RFTOOLS_DIMENSION;
}
@Override
public String getWelcomeMessage() {
return "Entering the rftools dimension!";
}
@Override
public boolean canRespawnHere() {
return false;
}
@Override
public int getRespawnDimension(EntityPlayerMP player) {
getDimensionInformation();
if (DimletConfiguration.respawnSameDim || (dimensionInformation != null && dimensionInformation.isRespawnHere())) {
DimensionStorage dimensionStorage = DimensionStorage.getDimensionStorage(worldObj);
int power = dimensionStorage.getEnergyLevel(dimensionId);
if (power < 1000) {
return DimletConfiguration.spawnDimension;
} else {
return dimensionId;
}
}
return DimletConfiguration.spawnDimension;
}
@Override
public IChunkProvider createChunkGenerator() {
int dim = worldObj.provider.dimensionId;
setSeed(dim);
return new GenericChunkProvider(worldObj, seed);
}
@Override
public BiomeGenBase getBiomeGenForCoords(int x, int z) {
return super.getBiomeGenForCoords(x, z);
}
@Override
public int getActualHeight() {
return 256;
}
private static long lastFogTime = 0;
@Override
@SideOnly(Side.CLIENT)
public Vec3 getFogColor(float angle, float dt) {
int dim = worldObj.provider.dimensionId;
if (System.currentTimeMillis() - lastFogTime > 1000) {
lastFogTime = System.currentTimeMillis();
RFToolsMessages.INSTANCE.sendToServer(new PacketGetDimensionEnergy(dim));
}
float factor = calculatePowerBlackout(dim);
getDimensionInformation();
float r;
float g;
float b;
if (dimensionInformation == null) {
r = g = b = 1.0f;
} else {
r = dimensionInformation.getSkyDescriptor().getFogColorFactorR() * factor;
g = dimensionInformation.getSkyDescriptor().getFogColorFactorG() * factor;
b = dimensionInformation.getSkyDescriptor().getFogColorFactorB() * factor;
}
Vec3 color = super.getFogColor(angle, dt);
return Vec3.createVectorHelper(color.xCoord * r, color.yCoord * g, color.zCoord * b);
}
private static long lastTime = 0;
@Override
@SideOnly(Side.CLIENT)
public Vec3 getSkyColor(Entity cameraEntity, float partialTicks) {
int dim = worldObj.provider.dimensionId;
if (System.currentTimeMillis() - lastTime > 1000) {
lastTime = System.currentTimeMillis();
RFToolsMessages.INSTANCE.sendToServer(new PacketGetDimensionEnergy(dim));
}
float factor = calculatePowerBlackout(dim);
getDimensionInformation();
float r;
float g;
float b;
if (dimensionInformation == null) {
r = g = b = 1.0f;
} else {
r = dimensionInformation.getSkyDescriptor().getSkyColorFactorR() * factor;
g = dimensionInformation.getSkyDescriptor().getSkyColorFactorG() * factor;
b = dimensionInformation.getSkyDescriptor().getSkyColorFactorB() * factor;
}
Vec3 skyColor = super.getSkyColor(cameraEntity, partialTicks);
return Vec3.createVectorHelper(skyColor.xCoord * r, skyColor.yCoord * g, skyColor.zCoord * b);
}
private float calculatePowerBlackout(int dim) {
float factor = 1.0f;
int power = storage.getEnergyLevel(dim);
if (power < DimletConfiguration.DIMPOWER_WARN3) {
factor = ((float) power) / DimletConfiguration.DIMPOWER_WARN3 * 0.2f;
} else if (power < DimletConfiguration.DIMPOWER_WARN2) {
factor = (float) (power - DimletConfiguration.DIMPOWER_WARN3) / (DimletConfiguration.DIMPOWER_WARN2 - DimletConfiguration.DIMPOWER_WARN3) * 0.3f + 0.2f;
} else if (power < DimletConfiguration.DIMPOWER_WARN1) {
factor = (float) (power - DimletConfiguration.DIMPOWER_WARN2) / (DimletConfiguration.DIMPOWER_WARN1 - DimletConfiguration.DIMPOWER_WARN2) * 0.3f + 0.5f;
} else if (power < DimletConfiguration.DIMPOWER_WARN0) {
factor = (float) (power - DimletConfiguration.DIMPOWER_WARN1) / (DimletConfiguration.DIMPOWER_WARN0 - DimletConfiguration.DIMPOWER_WARN1) * 0.2f + 0.8f;
}
return factor;
}
@Override
@SideOnly(Side.CLIENT)
public float getSunBrightness(float par1) {
getDimensionInformation();
if (dimensionInformation == null) {
return super.getSunBrightness(par1);
}
int dim = worldObj.provider.dimensionId;
float factor = calculatePowerBlackout(dim);
return super.getSunBrightness(par1) * dimensionInformation.getSkyDescriptor().getSunBrightnessFactor() * factor;
}
@Override
@SideOnly(Side.CLIENT)
public float getStarBrightness(float par1) {
getDimensionInformation();
if (dimensionInformation == null) {
return super.getStarBrightness(par1);
}
return super.getStarBrightness(par1) * dimensionInformation.getSkyDescriptor().getStarBrightnessFactor();
}
@Override
public void updateWeather() {
super.updateWeather();
if (!worldObj.isRemote) {
getDimensionInformation();
if (dimensionInformation != null) {
WeatherDescriptor descriptor = dimensionInformation.getWeatherDescriptor();
float rs = descriptor.getRainStrength();
if (rs > -0.5f) {
worldObj.rainingStrength = rs;
if (Math.abs(worldObj.rainingStrength) < 0.001) {
worldObj.prevRainingStrength = 0;
worldObj.rainingStrength = 0;
worldObj.getWorldInfo().setRaining(false);
}
}
float ts = descriptor.getThunderStrength();
if (ts > -0.5f) {
worldObj.thunderingStrength = ts;
if (Math.abs(worldObj.thunderingStrength) < 0.001) {
worldObj.prevThunderingStrength = 0;
worldObj.thunderingStrength = 0;
worldObj.getWorldInfo().setThundering(false);
}
}
}
}
}
@Override
public float calculateCelestialAngle(long time, float dt) {
getDimensionInformation();
if (dimensionInformation == null) {
return super.calculateCelestialAngle(time, dt);
}
if (!dimensionInformation.getTerrainType().hasSky()) {
return 0.5F;
}
if (dimensionInformation.getCelestialAngle() == null) {
if (dimensionInformation.getTimeSpeed() == null) {
return super.calculateCelestialAngle(time, dt);
} else {
return super.calculateCelestialAngle((long) (time * dimensionInformation.getTimeSpeed()), dt);
}
} else {
return dimensionInformation.getCelestialAngle();
}
}
//------------------------ RFToolsWorldProvider
@Override
public int getCurrentRF() {
DimensionStorage dimensionStorage = DimensionStorage.getDimensionStorage(worldObj);
return dimensionStorage.getEnergyLevel(dimensionId);
}
}