nightkosh.gravestone.helper.GraveGenerationHelper.java Source code

Java tutorial

Introduction

Here is the source code for nightkosh.gravestone.helper.GraveGenerationHelper.java

Source

package nightkosh.gravestone.helper;

import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Enchantments;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import nightkosh.gravestone.api.IGraveStoneHelper;
import nightkosh.gravestone.api.death_handler.ICustomEntityDeathHandler;
import nightkosh.gravestone.api.grave.EnumGraveMaterial;
import nightkosh.gravestone.api.grave.EnumGraveType;
import nightkosh.gravestone.api.grave_items.*;
import nightkosh.gravestone.block.BlockGraveStone;
import nightkosh.gravestone.block.enums.EnumGraves;
import nightkosh.gravestone.config.Config;
import nightkosh.gravestone.core.GSBlock;
import nightkosh.gravestone.core.MobHandler;
import nightkosh.gravestone.core.compatibility.CompatibilityBattlegear;
import nightkosh.gravestone.core.compatibility.CompatibilityTwilightForest;
import nightkosh.gravestone.core.logger.GSLogger;
import nightkosh.gravestone.helper.api.APIGraveGeneration;
import nightkosh.gravestone.inventory.GraveInventory;
import nightkosh.gravestone.tileentity.DeathMessageInfo;
import nightkosh.gravestone.tileentity.TileEntityGraveStone;

import java.util.*;

/**
 * GraveStone mod
 *
 * @author NightKosh
 * @license Lesser GNU Public License v3 (http://www.gnu.org/licenses/lgpl.html)
 */
public class GraveGenerationHelper implements IGraveStoneHelper {
    public static final IGraveStoneHelper INSTANCE = new GraveGenerationHelper();

    protected static final Random rand = new Random();

    public static ArrayList<Item> swordsList = new ArrayList<>(Arrays.asList(Items.WOODEN_SWORD, Items.STONE_SWORD,
            Items.IRON_SWORD, Items.GOLDEN_SWORD, Items.DIAMOND_SWORD));

    public enum EnumGraveTypeByEntity {
        ALL_GRAVES, PLAYER_GRAVES, VILLAGERS_GRAVES, HUMAN_GRAVES, PETS_GRAVES, DOGS_GRAVES, CATS_GRAVES, HORSE_GRAVES
    }

    @Override
    public void addSwordToSwordsList(Item sword) {
        if (sword != null) {
            swordsList.add(sword);
        }
    }

    private static final EnumGraveType[] GENERATED_PLAYER_GRAVES_TYPES = { EnumGraveType.VERTICAL_PLATE,
            EnumGraveType.CROSS, EnumGraveType.OBELISK, EnumGraveType.CELTIC_CROSS,
            EnumGraveType.HORIZONTAL_PLATE };
    private static final EnumGraveType[] STARVED_PLAYER_GRAVES_TYPES = { EnumGraveType.STARVED_CORPSE, };
    private static final EnumGraveType[] WITHERED_PLAYER_GRAVES_TYPES = { EnumGraveType.WITHERED_CORPSE, };
    private static final EnumGraveType[] GENERATED_VILLAGERS_GRAVES_TYPES = { EnumGraveType.VILLAGER_STATUE };
    private static final EnumGraveType[] GENERATED_DOGS_GRAVES_TYPES = { EnumGraveType.DOG_STATUE };
    private static final EnumGraveType[] GENERATED_CAT_GRAVES_TYPES = { EnumGraveType.CAT_STATUE };
    private static final EnumGraveType[] GENERATED_HORSE_GRAVES_TYPES = { EnumGraveType.HORSE_STATUE };
    private static final EnumGraveType[] GENERATED_CREEPER_STATUES_GRAVES_TYPES = { EnumGraveType.CREEPER_STATUE };

    private static void addNonEmptyItems(List<ItemStack> items, NonNullList<ItemStack> itemsToAdd) {
        for (ItemStack stack : itemsToAdd) {
            if (!stack.isEmpty()) {
                items.add(stack);
            }
        }
    }

    public static void createPlayerGrave(EntityPlayer player, LivingDeathEvent event, long spawnTime) {
        if (player.getEntityWorld() != null && !player.getEntityWorld().getGameRules().getBoolean("keepInventory")
                && Config.graveItemsCount > 0
                && !isInRestrictedArea(player.getEntityWorld(), player.getPosition())) {
            List<ItemStack> items = new ArrayList<>(41);

            //            GSCompatibilityAntiqueAtlas.placeDeathMarkerAtDeath(player); //TODO !!!!!!!!!!!!

            addNonEmptyItems(items, player.inventory.mainInventory);
            addNonEmptyItems(items, player.inventory.armorInventory);
            addNonEmptyItems(items, player.inventory.offHandInventory);
            //            items.addAll(player.inventory.mainInventory);
            //            items.addAll(player.inventory.armorInventory);
            //            items.addAll(player.inventory.offHandInventory);

            CompatibilityTwilightForest.addSlotTags(items);
            CompatibilityBattlegear.addItems(items, player);

            if (!CompatibilityTwilightForest.handleCharmsOfKeeping(items, player)) {
                player.inventory.clear();
            }

            for (IPlayerItems additionalItems : APIGraveGeneration.PLAYER_ITEMS) {
                try {
                    List<ItemStack> modItems = additionalItems.addItems(player, event.getSource());
                    if (modItems != null && !modItems.isEmpty() && modItems.size() != 0) {
                        items.addAll(modItems);
                    }
                } catch (Exception e) {
                    GSLogger.logError("Compatibility error occurred in additionalItems.addItems");
                    e.printStackTrace();
                }
            }

            //TODO is it really required??
            CompatibilityTwilightForest.removeSlotTags(items);

            // remove some items by other mods
            for (IPlayerItems additionalItems : APIGraveGeneration.PLAYER_ITEMS) {
                try {
                    additionalItems.getItems(player, event.getSource(), items);
                } catch (Exception e) {
                    GSLogger.logError("Compatibility error occurred in additionalItems.getItems");
                    e.printStackTrace();
                }
            }

            // remove items with Curse of Vanishing enchantment
            if (Config.removeCurseOfVanishingItems) {
                for (int i = 0; i < items.size(); i++) {
                    if (EnchantmentHelper.hasEnchantment(items.get(i), Enchantments.VANISHING_CURSE)) {
                        items.set(i, ItemStack.EMPTY);
                    }
                }
            }

            if (Config.generateEmptyPlayerGraves || items.size() != 0) {
                createGrave(player, event, items, EnumGraveTypeByEntity.PLAYER_GRAVES, false, spawnTime);
            }
        } else if (Config.generateEmptyPlayerGraves) {
            createGrave(player, event, null, EnumGraveTypeByEntity.PLAYER_GRAVES, false, spawnTime);
        }
    }

    public static void createVillagerGrave(EntityVillager villager, LivingDeathEvent event) {
        List<ItemStack> items = new ArrayList<>(5);
        for (IVillagerItems additionalItems : APIGraveGeneration.VILLAGER_ITEMS) {
            items.addAll(additionalItems.addItems(villager, event.getSource()));
        }

        IItemHandler itemHandler = villager.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
                villager.getHorizontalFacing());
        if (villager.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, villager.getHorizontalFacing())) {
            for (int slot = 0; slot < itemHandler.getSlots(); slot++) {
                ItemStack stack = itemHandler.extractItem(slot, 100500, false);
                if (stack != null && !stack.isEmpty()) {
                    items.add(stack);
                }
            }
        }

        long spawnTime = MobHandler.getAndRemoveSpawnTime(event.getEntity());
        createGrave(villager, event, items, GraveGenerationHelper.EnumGraveTypeByEntity.VILLAGERS_GRAVES, true,
                spawnTime);
    }

    public static void createDogGrave(EntityWolf dog, LivingDeathEvent event) {
        if (dog.isTamed()) {
            long spawnTime = MobHandler.getAndRemoveSpawnTime(event.getEntity());
            createGrave(dog, event, getDogsItems(dog, event), EnumGraveTypeByEntity.DOGS_GRAVES, false, spawnTime);
        }
    }

    public static void createCatGrave(EntityOcelot cat, LivingDeathEvent event) {
        if (cat.isTamed()) {
            long spawnTime = MobHandler.getAndRemoveSpawnTime(event.getEntity());
            createGrave(cat, event, getCatsItems(cat, event), EnumGraveTypeByEntity.CATS_GRAVES, false, spawnTime);
        }
    }

    private static List<ItemStack> getDogsItems(EntityWolf dog, LivingDeathEvent event) {
        List<ItemStack> items = new ArrayList<>(5);
        for (IDogItems additionalItems : APIGraveGeneration.DOG_ITEMS) {
            items.addAll(additionalItems.addItems(dog, event.getSource()));
        }

        IItemHandler itemHandler = dog.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
                dog.getHorizontalFacing());
        if (dog.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dog.getHorizontalFacing())) {
            for (int slot = 0; slot < itemHandler.getSlots(); slot++) {
                ItemStack stack = itemHandler.extractItem(slot, 100500, false);
                if (stack != null && !stack.isEmpty()) {
                    items.add(stack);
                }
            }
        }
        return items;
    }

    private static List<ItemStack> getCatsItems(EntityOcelot cat, LivingDeathEvent event) {
        List<ItemStack> items = new ArrayList<>(5);
        for (ICatItems additionalItems : APIGraveGeneration.CAT_ITEMS) {
            items.addAll(additionalItems.addItems(cat, event.getSource()));
        }

        IItemHandler itemHandler = cat.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
                cat.getHorizontalFacing());
        if (cat.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, cat.getHorizontalFacing())) {
            for (int slot = 0; slot < itemHandler.getSlots(); slot++) {
                ItemStack stack = itemHandler.extractItem(slot, 100500, false);
                if (stack != null && !stack.isEmpty()) {
                    items.add(stack);
                }
            }
        }
        return items;
    }

    public static void createHorseGrave(AbstractHorse horse, LivingDeathEvent event) {
        if (horse.isTame()) {
            List<ItemStack> items = new ArrayList<>();
            items.addAll(getHorseItems(horse));

            for (IHorseItems additionalItems : APIGraveGeneration.HORSE_ITEMS) {
                items.addAll(additionalItems.addItems(horse, event.getSource()));
            }

            long spawnTime = MobHandler.getAndRemoveSpawnTime(event.getEntity());
            createGrave(horse, event, items, EnumGraveTypeByEntity.HORSE_GRAVES, false, spawnTime);
        }
    }

    private static List<ItemStack> getHorseItems(AbstractHorse horse) {
        List<ItemStack> items = new ArrayList<>();

        IItemHandler itemHandler = horse.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
                horse.getHorizontalFacing());
        if (horse.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, horse.getHorizontalFacing())) {
            for (int slot = 0; slot < itemHandler.getSlots(); slot++) {
                ItemStack stack = itemHandler.extractItem(slot, 100500, false);
                if (stack != null && !stack.isEmpty()) {
                    items.add(stack);
                }
            }
        }

        return items;
    }

    public static void createGrave(Entity entity, LivingDeathEvent event, List<ItemStack> items,
            EnumGraveTypeByEntity graveTypeByEntity, boolean isVillager, long spawnTime) {
        if (isInRestrictedArea(entity.getEntityWorld(), entity.getPosition())) {
            GSLogger.logInfo("Can't generate " + entity.getName() + "'s grave in restricted area. "
                    + entity.getPosition().toString());
            if (items != null) {
                items.stream().filter(item -> item != null).forEach(item -> {
                    GraveInventory.dropItem(item, entity.getEntityWorld(), entity.getPosition());
                });
            }
        } else {
            int age = (int) (entity.getEntityWorld().getWorldTime() - spawnTime) / 24000;
            BlockPos pos = new BlockPos(entity.posX, Math.round(entity.posY), entity.posZ - 1);
            GraveInfoOnDeath graveInfo = getGraveOnDeath(entity.getEntityWorld(), pos, entity, graveTypeByEntity,
                    items, age, event.getSource());
            DeathMessageInfo messageInfo = getDeathMessage((EntityLivingBase) entity, event.getSource().damageType,
                    isVillager);
            createOnDeath(entity, entity.getEntityWorld(), pos, messageInfo, items, age, graveInfo,
                    event.getSource());
        }
    }

    public static void createCustomGrave(Entity entity, LivingDeathEvent event,
            ICustomEntityDeathHandler customEntityDeathHandler) {
        if (isInRestrictedArea(entity.getEntityWorld(), entity.getPosition())) {
            GSLogger.logInfo("Can't generate " + entity.getName() + "'s grave in restricted area. "
                    + entity.getPosition().toString());
            if (customEntityDeathHandler.getItems() != null) {
                customEntityDeathHandler.getItems().stream().filter(item -> item != null).forEach(item -> {
                    GraveInventory.dropItem(item, entity.getEntityWorld(), entity.getPosition());
                });
            }
        } else {
            int age = customEntityDeathHandler.getAge();
            GraveInfoOnDeath graveInfo = new GraveInfoOnDeath();
            graveInfo.setGrave(EnumGraves.getByTypeAndMaterial(
                    customEntityDeathHandler.getGraveType(entity, event.getSource()),
                    customEntityDeathHandler.getGraveMaterial(entity, event.getSource())));
            graveInfo.setSword(customEntityDeathHandler.getSword());
            graveInfo.setEnchanted(customEntityDeathHandler.isEnchanted(entity, event.getSource()));
            graveInfo.setMossy(customEntityDeathHandler.isMossy(entity, event.getSource()));

            BlockPos pos = new BlockPos(entity.posX, Math.round(entity.posY), entity.posZ - 1);
            DeathMessageInfo messageInfo = getDeathMessage((EntityLivingBase) entity, event.getSource().damageType,
                    false);
            createOnDeath(entity, entity.getEntityWorld(), pos, messageInfo, customEntityDeathHandler.getItems(),
                    age, graveInfo, event.getSource());
        }
    }

    private static GraveInfoOnDeath getGraveOnDeath(World world, BlockPos pos, Entity entity,
            EnumGraveTypeByEntity graveTypeByEntity, List<ItemStack> items, int age, DamageSource damageSource) {
        GraveInfoOnDeath graveInfo = new GraveInfoOnDeath();
        if (chooseGraveTypeByAgeOrLevel(entity, graveTypeByEntity, age)) {
            EnumGraveMaterial material = getGraveMaterialByAgeOrLevel(entity, age, graveTypeByEntity);
            EnumGraveType[] type;
            if (isExplosionDamage(damageSource)) {
                type = GENERATED_CREEPER_STATUES_GRAVES_TYPES;
            } else {
                type = getDefaultGraveTypes(graveTypeByEntity);
            }

            graveInfo.grave = getGraveType(type, material);
        } else {
            graveInfo.grave = getGraveByDeath(damageSource, graveTypeByEntity, entity, age);
            if (graveInfo.grave == null) {
                if (graveTypeByEntity == EnumGraveTypeByEntity.PLAYER_GRAVES && Config.generateSwordGraves
                        && world.rand.nextInt(4) == 0
                        && graveTypeByEntity.equals(EnumGraveTypeByEntity.PLAYER_GRAVES)) {
                    ItemStack sword = getSwordFromInventory(items);
                    if (sword != null) {
                        graveInfo.sword = sword;
                        graveInfo.grave = EnumGraves.SWORD;
                    }
                }

                if (graveInfo.grave == null) {
                    graveInfo.grave = getGraveTypeByBiomes(world, pos, graveTypeByEntity, damageSource);
                }
            }
        }

        graveInfo.setMossy(isMossyGrave(world, pos, graveInfo.grave.getMaterial()));
        graveInfo.setEnchanted(INSTANCE.isMagicDamage(damageSource));

        return graveInfo;
    }

    private static class GraveInfoOnDeath {
        private EnumGraves grave;
        private ItemStack sword;
        private boolean enchanted;
        private boolean mossy;

        public EnumGraves getGrave() {
            return grave;
        }

        public ItemStack getSword() {
            return sword;
        }

        public boolean isEnchanted() {
            return enchanted;
        }

        public boolean isMossy() {
            return mossy;
        }

        public void setGrave(EnumGraves grave) {
            this.grave = grave;
        }

        public void setSword(ItemStack sword) {
            this.sword = sword;
        }

        public void setEnchanted(boolean enchanted) {
            this.enchanted = enchanted;
        }

        public void setMossy(boolean mossy) {
            this.mossy = mossy;
        }
    }

    private static void createOnDeath(Entity entity, World world, BlockPos pos, DeathMessageInfo deathInfo,
            List<ItemStack> items, int age, GraveInfoOnDeath graveInfo, DamageSource damageSource) {
        EnumFacing direction = EnumFacing
                .getHorizontal(MathHelper.floor((double) (entity.rotationYaw * 4 / 360F) + 0.5) & 3);

        BlockPos newPos = findPlaceForGrave(world, pos);
        if (newPos != null) {
            world.setBlockState(newPos,
                    GSBlock.GRAVE_STONE.getDefaultState().withProperty(BlockGraveStone.FACING, direction), 2);
            TileEntityGraveStone tileEntity = (TileEntityGraveStone) world.getTileEntity(newPos);

            if (tileEntity != null) {
                if (graveInfo.getSword() != null) {
                    tileEntity.setSword(graveInfo.getSword());
                }

                tileEntity.getDeathTextComponent().setLocalized();
                tileEntity.getDeathTextComponent().setName(deathInfo.getName());
                tileEntity.getDeathTextComponent().setDeathText(deathInfo.getDeathMessage());
                tileEntity.getDeathTextComponent().setKillerName(deathInfo.getKillerName());
                tileEntity.getInventory().setItems(items);
                tileEntity.setGraveType(graveInfo.getGrave().ordinal());
                tileEntity.setAge(age);
                tileEntity.setEnchanted(graveInfo.isEnchanted());
                tileEntity.setMossy(graveInfo.isMossy());
                if (entity instanceof EntityPlayer) {
                    tileEntity.setOwner(entity.getUniqueID().toString());
                } else if (entity instanceof EntityTameable && ((EntityTameable) entity).isTamed()
                        && ((EntityTameable) entity).getOwner() != null) {
                    tileEntity.setOwner(((EntityTameable) entity).getOwner().getUniqueID().toString());
                }
            }
            GSLogger.logInfoGrave("Create " + deathInfo.getName() + "'s grave at " + newPos.getX() + "x"
                    + newPos.getY() + "x" + newPos.getZ());
        } else {
            ItemStack itemStack = new ItemStack(Item.getItemFromBlock(GSBlock.GRAVE_STONE), 1);
            itemStack.setItemDamage(graveInfo.getGrave().ordinal());
            NBTTagCompound nbt = new NBTTagCompound();
            nbt.setBoolean("isLocalized", true);
            nbt.setString("name", deathInfo.getName());
            nbt.setString("DeathText", deathInfo.getDeathMessage());
            nbt.setString("KillerName", deathInfo.getKillerNameForTE());
            nbt.setBoolean("Enchanted", graveInfo.isEnchanted());
            nbt.setBoolean("Mossy", graveInfo.isMossy());
            nbt.setInteger("Age", age);

            if (graveInfo.getGrave() == EnumGraves.SWORD) {
                GraveStoneHelper.addSwordInfo(nbt, graveInfo.getSword());
            }

            itemStack.setTagCompound(nbt);
            GraveInventory.dropItem(itemStack, world, pos);

            if (items != null) {
                for (ItemStack item : items) {
                    if (item != null) {
                        GraveInventory.dropItem(item, world, pos);
                    }
                }
            }
            GSLogger.logInfoGrave("Can not create " + deathInfo.getName() + "'s grave at " + pos.getX() + "x"
                    + pos.getY() + "x" + pos.getZ());
        }
    }

    private static DeathMessageInfo getDeathMessage(EntityLivingBase entity, String damageType,
            boolean isVillager) {
        EntityLivingBase killer = entity.getAttackingEntity();
        String shortString = "death.attack." + damageType;
        String fullString = shortString + ".player";

        String entityName = entity.getName();
        if (entityName == null) {
            entityName = "entity." + EntityList.getEntityString(entity) + ".name";
        }

        if (killer != null) {
            String killerName;
            if (killer instanceof EntityPlayer) {
                killerName = killer.getDisplayName().getFormattedText();
                if (isVillager) {
                    GSLogger.logInfoGrave("Villager was killed by " + killerName);
                }
            } else {
                killerName = EntityList.getEntityString(killer);
                if (killerName == null) {
                    killerName = "entity.generic.name";
                } else {
                    killerName = "entity." + killerName + ".name";
                }
            }
            if (I18n.canTranslate(fullString)) {
                return new DeathMessageInfo(entityName, fullString, killerName);
            } else {
                return new DeathMessageInfo(entityName, shortString, killerName);
            }
        } else {
            return new DeathMessageInfo(entityName, shortString, null);
        }
    }

    private static boolean isInRestrictedArea(World world, BlockPos pos) {
        return Config.restrictGraveGenerationInArea.stream().anyMatch((area) -> area.isInArea(world, pos));
    }

    @Override
    public boolean isMagicDamage(DamageSource damageSource) {
        return DamageSource.MAGIC.equals(damageSource) || damageSource.damageType.toLowerCase().contains("magic");
    }

    @Override
    public boolean isMossyGrave(World world, BlockPos pos, EnumGraveMaterial graveMaterial,
            EnumGraveType graveType) {
        return isMossyGrave(world, pos, EnumGraves.getByTypeAndMaterial(graveType, graveMaterial).getMaterial());
    }

    public static boolean isMossyGrave(World world, BlockPos pos, EnumGraveMaterial graveMaterial) {
        Set<BiomeDictionary.Type> biomeTypesList = BiomeDictionary.getTypes(world.getBiome(pos));
        return graveMaterial != EnumGraveMaterial.OTHER && (biomeTypesList.contains(BiomeDictionary.Type.JUNGLE)
                || biomeTypesList.contains(BiomeDictionary.Type.SWAMP));
    }

    public static boolean chooseGraveTypeByAgeOrLevel(Entity entity, EnumGraveTypeByEntity graveTypeByEntity,
            int age) {
        if (graveTypeByEntity == EnumGraveTypeByEntity.PLAYER_GRAVES) {
            return ((EntityPlayer) entity).experienceLevel >= 15;
        } else {
            return age >= 30;
        }
    }

    public static EnumGraveMaterial getGraveMaterialByAgeOrLevel(Entity entity, int age,
            EnumGraveTypeByEntity graveTypeByEntity) {
        if (graveTypeByEntity == EnumGraveTypeByEntity.PLAYER_GRAVES) {
            return INSTANCE.getGraveMaterialByLevel(((EntityPlayer) entity).experienceLevel);
        } else {
            return INSTANCE.getGraveMaterialByAge(age);
        }
    }

    @Override
    public EnumGraveMaterial getGraveMaterialByLevel(int level) {
        if (level >= 65) {
            return EnumGraveMaterial.EMERALD;
        } else if (level >= 55) {
            return EnumGraveMaterial.DIAMOND;
        } else if (level >= 45) {
            return EnumGraveMaterial.REDSTONE;
        } else if (level >= 35) {
            return EnumGraveMaterial.GOLD;
        } else if (level >= 25) {
            return EnumGraveMaterial.LAPIS;
        } else {
            return EnumGraveMaterial.IRON;
        }
    }

    @Override
    public EnumGraveMaterial getGraveMaterialByAge(int age) {
        if (age > 180) {
            return EnumGraveMaterial.EMERALD;
        } else if (age > 150) {
            return EnumGraveMaterial.DIAMOND;
        } else if (age > 120) {
            return EnumGraveMaterial.REDSTONE;
        } else if (age > 90) {
            return EnumGraveMaterial.GOLD;
        } else if (age > 60) {
            return EnumGraveMaterial.LAPIS;
        } else {
            return EnumGraveMaterial.IRON;
        }
    }

    protected static EnumGraveType[] getDefaultGraveTypes(EnumGraveTypeByEntity graveTypeByEntity) {
        switch (graveTypeByEntity) {
        case VILLAGERS_GRAVES:
            return GENERATED_VILLAGERS_GRAVES_TYPES;
        case DOGS_GRAVES:
            return GENERATED_DOGS_GRAVES_TYPES;
        case CATS_GRAVES:
            return GENERATED_CAT_GRAVES_TYPES;
        case HORSE_GRAVES:
            return GENERATED_HORSE_GRAVES_TYPES;
        default:
        case PLAYER_GRAVES:
            return GENERATED_PLAYER_GRAVES_TYPES;
        }
    }

    public static EnumGraves getGraveByDeath(DamageSource damageSource, EnumGraveTypeByEntity graveTypeByEntity,
            Entity entity, int age) {
        EnumGraveType[] graveTypes = null;
        EnumGraveMaterial material;

        if (isFireDamage(damageSource, damageSource.damageType)
                || isLavaDamage(damageSource, damageSource.damageType)) {
            material = EnumGraveMaterial.OBSIDIAN;
        } else if (graveTypeByEntity == EnumGraveTypeByEntity.PLAYER_GRAVES) {
            //TODO drown
            if (DamageSource.STARVE.equals(damageSource)) {
                graveTypes = STARVED_PLAYER_GRAVES_TYPES;
                material = EnumGraveMaterial.OTHER;
            } else if (DamageSource.WITHER.equals(damageSource)) {
                graveTypes = WITHERED_PLAYER_GRAVES_TYPES;
                material = EnumGraveMaterial.OTHER;
            } else {
                return null;
            }
        } else {
            return null;
        }

        if (graveTypes == null) {
            graveTypes = getDefaultGraveTypes(graveTypeByEntity);
        }

        return getGraveType(graveTypes, material);
    }

    public static boolean isFireDamage(DamageSource damageSource, String damageType) {
        return DamageSource.IN_FIRE.equals(damageSource) || DamageSource.ON_FIRE.equals(damageSource)
                || isFireDamage(damageType);
    }

    public static boolean isFireDamage(String damageType) {
        return damageType.toLowerCase().contains("nfire");
    }

    public static boolean isLavaDamage(DamageSource damageSource, String damageType) {
        return DamageSource.LAVA.equals(damageSource) || isLavaDamage(damageType);
    }

    public static boolean isLavaDamage(String damageType) {
        return damageType.toLowerCase().contains("lava");
    }

    public static boolean isMagicDamage(String damageText) {
        return damageText.toLowerCase().contains("magic");
    }

    public static boolean isExplosionDamage(DamageSource damageSource) {
        return isBlastDamage(damageSource.damageType) || isFireballDamage(damageSource.damageType);
    }

    public static boolean isBlastDamage(String damageType) {
        return damageType.toLowerCase().contains("explosion");
    }

    public static boolean isFireballDamage(String damageType) {
        return damageType.toLowerCase().contains("fireball");
    }

    public static EnumGraveMaterial[] getGraveMaterialByBiomes(World world, BlockPos pos) {
        Set<BiomeDictionary.Type> biomeTypesList = BiomeDictionary.getTypes(world.getBiome(pos));

        ArrayList<EnumGraveMaterial> materials = new ArrayList<>();
        if (biomeTypesList.contains(BiomeDictionary.Type.SANDY)
                || biomeTypesList.contains(BiomeDictionary.Type.BEACH)) {
            materials.add(EnumGraveMaterial.SANDSTONE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.JUNGLE)
                || biomeTypesList.contains(BiomeDictionary.Type.SWAMP)) {
            materials.add(EnumGraveMaterial.STONE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.MOUNTAIN)) {
            materials.add(EnumGraveMaterial.GRANITE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.HILLS)) {
            materials.add(EnumGraveMaterial.ANDESITE);
            materials.add(EnumGraveMaterial.DIORITE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.PLAINS)
                || biomeTypesList.contains(BiomeDictionary.Type.MUSHROOM)) {
            materials.add(EnumGraveMaterial.STONE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.FOREST)) {
            materials.add(EnumGraveMaterial.WOOD);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.SNOWY)) {
            materials.add(EnumGraveMaterial.ICE);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.NETHER)) {
            materials.add(EnumGraveMaterial.QUARTZ);
        }
        if (biomeTypesList.contains(BiomeDictionary.Type.MESA)) {
            materials.add(EnumGraveMaterial.RED_SANDSTONE);
        }
        // TODO if (biomeTypesList.contains(BiomeDictionary.Type.END)) {} ????????
        if (biomeTypesList.contains(BiomeDictionary.Type.WATER)) {
            materials.add(EnumGraveMaterial.PRIZMARINE);
        }

        if (materials.isEmpty()) {
            materials.add(EnumGraveMaterial.STONE);
        }

        EnumGraveMaterial[] materialsArray = new EnumGraveMaterial[materials.size()];
        return materials.toArray(materialsArray);
    }

    public static EnumGraves getGraveTypeByBiomes(World world, BlockPos pos,
            EnumGraveTypeByEntity graveTypeByEntity, DamageSource damageSource) {
        EnumGraveMaterial[] materialsArray = getGraveMaterialByBiomes(world, pos);

        EnumGraveType[] type;
        if (damageSource != null && isExplosionDamage(damageSource)) {
            type = GENERATED_CREEPER_STATUES_GRAVES_TYPES;
        } else {
            type = getDefaultGraveTypes(graveTypeByEntity);
        }
        return getGraveType(type, materialsArray);
    }

    private static BlockPos findPlaceForGrave(World world, BlockPos pos) {
        int x = pos.getX();
        int y = pos.getY();
        int z = pos.getZ();
        int newY = getGround(world, x, y, z);

        if (canGenerateGraveAtCoordinates(world, new BlockPos(x, newY, z))) {
            return new BlockPos(x, newY, z);
        } else {
            int dx = 1;
            int dz = 1;

            while (Math.abs(dx) < 9 && Math.abs(dz) < 9) {
                if (dx < 0) {
                    for (int newX = x - 1; newX >= x + dx; newX--) {
                        newY = getGround(world, newX, y, z);
                        if (canGenerateGraveAtCoordinates(world, new BlockPos(newX, newY, z))) {
                            return new BlockPos(newX, newY, z);
                        }
                    }
                } else {
                    for (int newX = x + 1; newX <= x + dx; newX++) {
                        newY = getGround(world, newX, y, z);
                        if (canGenerateGraveAtCoordinates(world, new BlockPos(newX, newY, z))) {
                            return new BlockPos(newX, newY, z);
                        }
                    }
                }
                x += dx;

                if (dz < 0) {
                    for (int newZ = z - 1; newZ >= z + dz; newZ--) {
                        newY = getGround(world, x, y, newZ);
                        if (canGenerateGraveAtCoordinates(world, new BlockPos(x, newY, newZ))) {
                            return new BlockPos(x, newY, newZ);
                        }
                    }
                } else {
                    for (int newZ = z + 1; newZ <= z + dz; newZ++) {
                        newY = getGround(world, x, y, newZ);
                        if (canGenerateGraveAtCoordinates(world, new BlockPos(x, newY, newZ))) {
                            return new BlockPos(x, newY, newZ);
                        }
                    }
                }
                z += dz;

                if (dx < 0) {
                    dx = Math.abs(dx) + 1;
                } else {
                    dx = (dx + 1) * -1;
                }

                if (dz < 0) {
                    dz = Math.abs(dz) + 1;
                } else {
                    dz = (dz + 1) * -1;
                }

            }
        }

        return null;
    }

    private static int getGround(World world, int x, int y, int z) {
        while (true) {
            BlockPos pos = new BlockPos(x, y - 1, z);
            IBlockState state = world.getBlockState(pos);
            if ((world.isAirBlock(pos) || state.getBlock().getMaterial(state).isLiquid()
                    || state.getBlock().getMaterial(state).isReplaceable()) && y > 1) {
                y--;
            } else {
                return y;
            }
        }
    }

    private static boolean canGenerateGraveAtCoordinates(World world, BlockPos pos) {
        IBlockState state = world.getBlockState(pos);
        IBlockState stateDown = world.getBlockState(pos.down());
        return stateDown.getBlock().getMaterial(stateDown).isSolid()
                && (world.isAirBlock(pos) || state.getBlock().getMaterial(state).isLiquid()
                        || state.getBlock().getMaterial(state).isReplaceable());
    }

    protected static EnumGraves getGraveType(EnumGraveType[] graveTypes, EnumGraveMaterial... materials) {
        EnumGraveType graveType = graveTypes[rand.nextInt(graveTypes.length)];
        EnumGraveMaterial material = materials[rand.nextInt(materials.length)];

        return EnumGraves.getByTypeAndMaterial(graveType, material);
    }

    private static ItemStack getSwordFromInventory(List<ItemStack> items) {
        if (items != null) {
            for (ItemStack stack : items) {
                if (stack != null && swordsList.contains(stack.getItem())) {
                    ItemStack sword = stack.copy();
                    items.remove(stack);
                    return sword;
                }
            }
        }

        return null;
    }
}