org.blockartistry.DynSurround.client.handlers.EnvironStateHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.blockartistry.DynSurround.client.handlers.EnvironStateHandler.java

Source

/*
 * This file is part of Dynamic Surroundings, licensed under the MIT License (MIT).
 *
 * Copyright (c) OreCruncher
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.blockartistry.DynSurround.client.handlers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import javax.annotation.Nonnull;

import org.apache.commons.lang3.StringUtils;
import org.blockartistry.DynSurround.DSurround;
import org.blockartistry.DynSurround.ModOptions;
import org.blockartistry.DynSurround.api.events.EnvironmentEvent;
import org.blockartistry.DynSurround.client.event.DiagnosticEvent;
import org.blockartistry.DynSurround.client.event.ServerDataEvent;
import org.blockartistry.DynSurround.client.handlers.scanners.BattleScanner;
import org.blockartistry.DynSurround.client.weather.WeatherProperties;
import org.blockartistry.DynSurround.registry.ArmorClass;
import org.blockartistry.DynSurround.registry.BiomeInfo;
import org.blockartistry.DynSurround.registry.BiomeRegistry;
import org.blockartistry.DynSurround.registry.DimensionInfo;
import org.blockartistry.DynSurround.registry.DimensionRegistry;
import org.blockartistry.DynSurround.registry.Evaluator;
import org.blockartistry.DynSurround.registry.RegistryManager;
import org.blockartistry.DynSurround.registry.SeasonRegistry;
import org.blockartistry.DynSurround.registry.SeasonType;
import org.blockartistry.DynSurround.registry.TemperatureRating;
import org.blockartistry.DynSurround.registry.RegistryManager.RegistryType;
import org.blockartistry.lib.MinecraftClock;
import org.blockartistry.lib.PlayerUtils;

import com.google.common.collect.ImmutableList;

import gnu.trove.procedure.TIntDoubleProcedure;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;

@Mod.EventBusSubscriber(value = Side.CLIENT, modid = DSurround.MOD_ID)
public class EnvironStateHandler extends EffectHandlerBase {

    // Diagnostic strings to display in the debug HUD
    private List<String> diagnostics = ImmutableList.of();

    // TPS status strings to display
    private List<String> serverDataReport = ImmutableList.of();

    public static class EnvironState {

        // State that is gathered from the various sources
        // to avoid requery. Used during the tick.
        private static String biomeName;
        private static BiomeInfo playerBiome = null;
        private static BiomeInfo truePlayerBiome = null;
        private static SeasonType season;
        private static int dimensionId;
        private static String dimensionName;
        private static DimensionInfo dimInfo = DimensionInfo.NONE;
        private static BlockPos playerPosition;
        private static EntityPlayer player;
        private static World world;
        private static boolean freezing;
        private static boolean humid;
        private static boolean dry;
        private static TemperatureRating playerTemperature;
        private static TemperatureRating biomeTemperature;
        private static boolean inside;
        private static ArmorClass armorClass;
        private static ArmorClass footArmorClass;
        private static boolean inVillage;

        private static boolean isUnderground;
        private static boolean isInSpace;
        private static boolean isInClouds;

        private static int lightLevel;
        private static int tickCounter;

        private static MinecraftClock clock = new MinecraftClock();
        private static BattleScanner battle = new BattleScanner();

        private static BlockPos getPlayerPos() {
            return new BlockPos(player.posX, player.getEntityBoundingBox().minY, player.posZ);
        }

        private static void reset() {
            final BiomeInfo WTF = RegistryManager.<BiomeRegistry>get(RegistryType.BIOME).WTF_INFO;
            biomeName = StringUtils.EMPTY;
            playerBiome = WTF;
            truePlayerBiome = WTF;
            season = SeasonType.NONE;
            dimensionId = 0;
            dimensionName = StringUtils.EMPTY;
            dimInfo = DimensionInfo.NONE;
            playerPosition = BlockPos.ORIGIN;
            player = null;
            world = null;
            freezing = false;
            humid = false;
            dry = false;
            playerTemperature = TemperatureRating.MILD;
            biomeTemperature = TemperatureRating.MILD;
            inside = false;
            armorClass = ArmorClass.NONE;
            footArmorClass = ArmorClass.NONE;
            inVillage = false;
            isUnderground = false;
            isInSpace = false;
            isInClouds = false;
            lightLevel = 0;
            tickCounter = 0;
            clock = new MinecraftClock();
            battle = new BattleScanner();
        }

        private static void tick(final World world, final EntityPlayer player) {

            final BiomeRegistry biomes = RegistryManager.<BiomeRegistry>get(RegistryType.BIOME);
            final SeasonRegistry seasons = RegistryManager.<SeasonRegistry>get(RegistryType.SEASON);
            final DimensionRegistry dimensions = RegistryManager.<DimensionRegistry>get(RegistryType.DIMENSION);

            EnvironState.player = player;
            EnvironState.world = player.world;
            EnvironState.dimInfo = dimensions.getData(player.world);
            EnvironState.clock.update(EnvironState.world);
            EnvironState.playerBiome = PlayerUtils.getPlayerBiome(player, false);
            EnvironState.biomeName = EnvironState.playerBiome.getBiomeName();
            EnvironState.season = seasons.getSeasonType(world);
            EnvironState.dimensionId = world.provider.getDimension();
            EnvironState.dimensionName = world.provider.getDimensionType().getName();
            EnvironState.playerPosition = getPlayerPos();
            EnvironState.inside = AreaSurveyHandler.isReallyInside();

            EnvironState.truePlayerBiome = PlayerUtils.getPlayerBiome(player, true);
            EnvironState.freezing = EnvironState.truePlayerBiome
                    .getFloatTemperature(EnvironState.playerPosition) < 0.15F;
            EnvironState.playerTemperature = seasons.getPlayerTemperature(world);
            EnvironState.biomeTemperature = seasons.getBiomeTemperature(world, getPlayerPosition());
            EnvironState.humid = EnvironState.truePlayerBiome.isHighHumidity();
            EnvironState.dry = EnvironState.truePlayerBiome.getRainfall() < 0.2F;

            EnvironState.armorClass = ArmorClass.effectiveArmorClass(player);
            EnvironState.footArmorClass = ArmorClass.footArmorClass(player);

            EnvironState.isUnderground = EnvironState.playerBiome == biomes.UNDERGROUND_INFO;
            EnvironState.isInSpace = EnvironState.playerBiome == biomes.OUTERSPACE_INFO;
            EnvironState.isInClouds = EnvironState.playerBiome == biomes.CLOUDS_INFO;

            final BlockPos pos = EnvironState.getPlayerPosition();
            final int blockLight = world.getLightFor(EnumSkyBlock.BLOCK, pos);
            final int skyLight = world.getLightFor(EnumSkyBlock.SKY, pos) - world.calculateSkylightSubtracted(1.0F);
            EnvironState.lightLevel = Math.max(blockLight, skyLight);

            // Trigger the battle scanner
            if (ModOptions.enableBattleMusic)
                EnvironState.battle.update();
            else
                EnvironState.battle.reset();

            if (!Minecraft.getMinecraft().isGamePaused())
                EnvironState.tickCounter++;
        }

        public static MinecraftClock getClock() {
            return clock;
        }

        public static BattleScanner getBattleScanner() {
            return battle;
        }

        public static DimensionInfo getDimensionInfo() {
            return dimInfo;
        }

        public static BiomeInfo getPlayerBiome() {
            return playerBiome;
        }

        public static BiomeInfo getTruePlayerBiome() {
            return truePlayerBiome;
        }

        public static String getBiomeName() {
            return biomeName;
        }

        public static SeasonType getSeason() {
            return season;
        }

        public static TemperatureRating getPlayerTemperature() {
            return playerTemperature;
        }

        public static TemperatureRating getBiomeTemperature() {
            return biomeTemperature;
        }

        public static int getDimensionId() {
            return dimensionId;
        }

        public static String getDimensionName() {
            return dimensionName;
        }

        public static EntityPlayer getPlayer() {
            return player;
        }

        public static World getWorld() {
            return world;
        }

        public static BlockPos getPlayerPosition() {
            return playerPosition;
        }

        public static boolean isPlayer(final Entity entity) {
            if (entity instanceof EntityPlayer) {
                final EntityPlayer ep = (EntityPlayer) entity;
                return player == null || ep.getUniqueID().equals(player.getUniqueID());
            }
            return false;
        }

        public static boolean isPlayer(final UUID id) {
            return player == null || player.getUniqueID().equals(id);
        }

        public static boolean isPlayer(final int id) {
            return player == null || player.getEntityId() == id;
        }

        public static boolean isCreative() {
            return player != null && player.capabilities.isCreativeMode;
        }

        public static boolean isPlayerHurt() {
            return player != null && ModOptions.playerHurtThreshold != 0 && !isCreative()
                    && player.getHealth() <= ModOptions.playerHurtThreshold;
        }

        public static boolean isPlayerHungry() {
            return player != null && ModOptions.playerHungerThreshold != 0 && !isCreative()
                    && player.getFoodStats().getFoodLevel() <= ModOptions.playerHungerThreshold;
        }

        public static boolean isPlayerBurning() {
            return player != null && player.isBurning();
        }

        public static boolean isPlayerSuffocating() {
            return player != null && player.getAir() <= 0;
        }

        public static boolean isPlayerFlying() {
            return player != null && player.capabilities.isFlying;
        }

        public static boolean isPlayerSprinting() {
            return player != null && player.isSprinting();
        }

        public static boolean isPlayerInLava() {
            return player != null && player.isInLava();
        }

        public static boolean isPlayerInvisible() {
            return player != null && player.isInvisible();
        }

        public static boolean isPlayerBlind() {
            return player != null && player.isPotionActive(MobEffects.BLINDNESS);
        }

        public static boolean isPlayerInWater() {
            return player != null && player.isInWater();
        }

        public static boolean isPlayerRiding() {
            return player != null && player.isRiding();
        }

        public static boolean isPlayerOnGround() {
            return player != null && player.onGround;
        }

        public static boolean isPlayerMoving() {
            return player != null && player.distanceWalkedModified != player.prevDistanceWalkedModified;
        }

        public static boolean isPlayerSneaking() {
            return player != null && player.isSneaking();
        }

        public static boolean isPlayerInside() {
            return inside;
        }

        public static boolean isPlayerUnderground() {
            return isUnderground;
        }

        public static boolean isPlayerInSpace() {
            return isInSpace;
        }

        public static boolean isPlayerInClouds() {
            return isInClouds;
        }

        public static boolean isFreezing() {
            return freezing;
        }

        public static boolean isHumid() {
            return humid;
        }

        public static boolean isDry() {
            return dry;
        }

        public static ArmorClass getPlayerArmorClass() {
            return armorClass;
        }

        public static ArmorClass getPlayerFootArmorClass() {
            return footArmorClass;
        }

        public static boolean inVillage() {
            return inVillage;
        }

        public static int getLightLevel() {
            return lightLevel;
        }

        public static int getTickCounter() {
            return tickCounter;
        }

        public static double distanceToPlayer(final double x, final double y, final double z) {
            return player != null ? player.getDistanceSq(x, y, z) : 0D;
        }
    }

    public EnvironStateHandler() {
        super("EnvironStateEffectHandler");
    }

    @Override
    public void process(@Nonnull final World world, @Nonnull final EntityPlayer player) {
        EnvironState.tick(world, player);

        // Gather diagnostics if needed
        if (Minecraft.getMinecraft().gameSettings.showDebugInfo && ModOptions.enableDebugLogging) {
            DSurround.getProfiler().startSection("GatherDebug");
            final DiagnosticEvent.Gather gather = new DiagnosticEvent.Gather(world, player);
            MinecraftForge.EVENT_BUS.post(gather);
            this.diagnostics = gather.output;
            DSurround.getProfiler().endSection();
        } else {
            this.diagnostics = null;
        }
    }

    /**
     * Hook the entity join world event so we can get the player and world info
     * ASAP.
     */
    @SubscribeEvent(priority = EventPriority.HIGHEST)
    public static void onEntityJoin(@Nonnull final EntityJoinWorldEvent event) {
        if (event.getWorld().isRemote && event.getEntity() instanceof EntityPlayerSP) {
            EnvironState.tick(event.getWorld(), (EntityPlayer) event.getEntity());
        }
    }

    @SubscribeEvent
    public void onEnvironmentEvent(@Nonnull final EnvironmentEvent event) {
        EnvironState.inVillage = event.inVillage;
    }

    /**
     * Hook the Forge text event to add on our diagnostics
     */
    @SubscribeEvent
    public void onGatherText(@Nonnull final RenderGameOverlayEvent.Text event) {
        if (this.diagnostics != null && !this.diagnostics.isEmpty()) {
            event.getLeft().add("");
            event.getLeft().addAll(this.diagnostics);
        }

        if (Minecraft.getMinecraft().gameSettings.showDebugInfo && this.serverDataReport != null) {
            event.getRight().add(" ");
            event.getRight().addAll(this.serverDataReport);
        }
    }

    @Override
    public void onConnect() {
        this.diagnostics = null;
        this.serverDataReport = null;
        EnvironState.reset();
    }

    @Override
    public void onDisconnect() {
        this.diagnostics = null;
        this.serverDataReport = null;
        EnvironState.reset();
    }

    // Use the new scripting system to pull out data to display
    // for debug. Good for testing.
    private final static String[] scripts = { "'Dim: ' + player.dimension + '/' + player.dimensionName",
            "'Biome: ' + biome.name + '; Temp ' + biome.temperature + '/' + biome.temperatureValue + ' rainfall: ' + biome.rainfall",
            "'Weather: ' + IF(weather.isRaining,'rainfall: ' + weather.rainfall,'not raining') + IF(weather.isThundering,' thundering','') + ' Temp: ' + weather.temperature + '/' + weather.temperatureValue",
            "'Season: ' + season  + IF(isNight,' night',' day') + IF(player.isInside,' inside',' outside')",
            "'Player: Temp ' + player.temperature + '; health ' + player.health + '/' + player.maxHealth + '; food ' + player.food.level + '; saturation ' + player.food.saturation + IF(player.isHurt,' isHurt','') + IF(player.isHungry,' isHungry','') + ' pos: (' + player.X + ',' + player.Y + ',' + player.Z + ') light: ' + player.lightLevel",
            "'Village: ' + player.inVillage" };

    @SubscribeEvent(priority = EventPriority.HIGHEST)
    public void diagnostics(final DiagnosticEvent.Gather event) {
        for (final String s : scripts) {
            final String result = Evaluator.eval(s).toString();
            event.output.add(result);
        }

        event.output.add(WeatherProperties.diagnostic());
        event.output.add("Aurora: " + (AuroraEffectHandler.getCurrentAurora() == null ? "NONE"
                : AuroraEffectHandler.getCurrentAurora().toString()));

        final List<String> badScripts = Evaluator.getNaughtyList();
        for (final String s : badScripts) {
            event.output.add("BAD SCRIPT: " + s);
        }
    }

    @Nonnull
    private static TextFormatting getTpsFormatPrefix(final int tps) {
        if (tps <= 10)
            return TextFormatting.RED;
        if (tps <= 15)
            return TextFormatting.YELLOW;
        return TextFormatting.GREEN;
    }

    @SubscribeEvent
    public void serverDataEvent(final ServerDataEvent event) {
        final ArrayList<String> data = new ArrayList<String>();

        final int diff = event.total - event.free;

        data.add(TextFormatting.GOLD + "Server Information");
        data.add(String.format("Mem: %d%% %03d/%3dMB", diff * 100 / event.max, diff, event.max));
        data.add(String.format("Allocated: %d%% %3dMB", event.total * 100 / event.max, event.total));
        final int tps = (int) Math.min(1000.0D / event.meanTickTime, 20.0D);
        data.add(String.format("Ticktime Overall:%s %5.3fms (%d TPS)", getTpsFormatPrefix(tps), event.meanTickTime,
                tps));
        event.dimTps.forEachEntry(new TIntDoubleProcedure() {
            @Override
            public boolean execute(int a, double b) {
                final String dimName = DimensionManager.getProviderType(a).getName();
                final int tps = (int) Math.min(1000.0D / b, 20.0D);
                data.add(String.format("%s (%d):%s %7.3fms (%d TPS)", dimName, a, getTpsFormatPrefix(tps), b, tps));
                return true;
            }

        });

        Collections.sort(data.subList(4, data.size()));
        this.serverDataReport = data;
    }

}