/**
Copyright (C) <2017> <coolAlias>
This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such,
you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package zeldaswordskills.block;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.block.Block;
import net.minecraft.block.BlockStone;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.statemap.IStateMapper;
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving.SpawnPlacementType;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumWorldBlockLayer;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import zeldaswordskills.api.block.BlockWeight;
import zeldaswordskills.api.block.IExplodable;
import zeldaswordskills.api.block.ISmashable;
import zeldaswordskills.block.tileentity.TileEntityDungeonStone;
import zeldaswordskills.client.ISwapModel;
import zeldaswordskills.client.render.block.ModelDungeonBlock;
import zeldaswordskills.creativetab.ZSSCreativeTabs;
import zeldaswordskills.item.ItemDungeonBlock;
import zeldaswordskills.ref.Config;
import zeldaswordskills.ref.Sounds;
import zeldaswordskills.util.PlayerUtils;
/**
*
* A simple block that renders as nearly any texture and can only be destroyed by explosions
*
*/
public class BlockDungeonStone extends Block implements ICustomStateMapper, IDungeonBlock, IExplodable, ISmashable, ISwapModel, ITileEntityProvider
{
public static final PropertyBool UNBREAKABLE = PropertyBool.create("unbreakable");
/** Stores the block state that will be rendered */
public static final UnlistedRenderBlock RENDER_BLOCK = new UnlistedRenderBlock();
public BlockDungeonStone(Material material) {
super(material);
setBlockUnbreakable();
setResistance(6.0F);
setStepSound(soundTypeStone);
setCreativeTab(ZSSCreativeTabs.tabBlocks);
setDefaultState(blockState.getBaseState().withProperty(UNBREAKABLE, Boolean.FALSE));
}
@Override
public TileEntity createNewTileEntity(World world, int meta) {
return new TileEntityDungeonStone();
}
@Override
public BlockWeight getSmashWeight(EntityPlayer player, ItemStack stack, IBlockState state, EnumFacing face) {
return (state.getValue(UNBREAKABLE).booleanValue() ? BlockWeight.IMPOSSIBLE : BlockWeight.VERY_HEAVY);
}
@Override
public Result onSmashed(World world, EntityPlayer player, ItemStack stack, BlockPos pos, IBlockState state, EnumFacing face) {
return Result.DEFAULT;
}
@Override
public boolean canEntityDestroy(IBlockAccess world, BlockPos pos, Entity entity) {
return !world.getBlockState(pos).getValue(UNBREAKABLE).booleanValue();
}
@Override
public boolean canCreatureSpawn(IBlockAccess world, BlockPos pos, SpawnPlacementType type) {
return false;
}
@Override
public int getMobilityFlag() {
return 2;
}
@Override
public boolean canHarvestBlock(IBlockAccess World, BlockPos pos, EntityPlayer player) {
return false;
}
@Override
public int damageDropped(IBlockState state) {
return state.getBlock().getMetaFromState(state);
}
@Override
public ArrayList<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) {
ArrayList<ItemStack> drops = new ArrayList<ItemStack>();
IBlockState renderState = ((IExtendedBlockState) state).getValue(RENDER_BLOCK);
if (renderState != null) {
int meta = renderState.getBlock().getMetaFromState(renderState);
drops.add(new ItemStack(renderState.getBlock(), 1, meta));
}
return drops;
}
@Override
public void onBlockClicked(World world, BlockPos pos, EntityPlayer player) {
if (!world.isRemote && player.getHeldItem() != null && player.getHeldItem().getItem() instanceof ItemPickaxe) {
if (Config.showSecretMessage) {
PlayerUtils.sendTranslatedChat(player, "chat.zss.block.secret");
}
world.playSoundAtEntity(player, Sounds.ITEM_BREAK, 0.25F, 1.0F / (world.rand.nextFloat() * 0.4F + 0.5F));
}
}
// this may not even be necessary, since these blocks will only ever be placed by a player
@Override
public void onBlockAdded(World world, BlockPos pos, IBlockState state) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof TileEntityDungeonStone) {
TileEntityDungeonStone stone = (TileEntityDungeonStone) te;
if (stone.getRenderState() == null) {
stone.setRenderState(getDefaultRenderState(((Boolean) state.getValue(UNBREAKABLE)).booleanValue()));
}
}
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase entity, ItemStack stack) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof TileEntityDungeonStone && stack != null && stack.getItem() instanceof ItemDungeonBlock) {
IBlockState renderState = ((ItemDungeonBlock) stack.getItem()).getBlockStateFromStack(stack);
if (renderState.getBlock() instanceof BlockDungeonStone) {
renderState = ((BlockDungeonStone) renderState.getBlock()).getDefaultRenderState(stack.getItemDamage() > 7);
}
((TileEntityDungeonStone) te).setRenderState(renderState);
}
}
// TODO remove if Mojang's stupid code ever gets fixed
@Override
public void onBlockExploded(World world, BlockPos pos, Explosion explosion) {
if (!world.getBlockState(pos).getValue(UNBREAKABLE).booleanValue()) {
super.onBlockExploded(world, pos, explosion);
}
}
@Override
public float getExplosionResistance(World world, BlockPos pos, Entity entity, Explosion explosion) {
IBlockState state = world.getBlockState(pos);
if (state.getBlock() != this) {
return state.getBlock().getExplosionResistance(world, pos, entity, explosion);
}
return (state.getValue(UNBREAKABLE).booleanValue() ? BlockWeight.getMaxResistance() : getExplosionResistance(entity));
}
@Override
public boolean isSameVariant(World world, BlockPos pos, IBlockState state, int meta) {
return true; // doesn't matter as this block is never used as a door anyway
}
@Override
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(UNBREAKABLE, Boolean.valueOf((meta & 0x8) > 0));
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(UNBREAKABLE).booleanValue() ? 0x8 : 0x0;
}
@Override
protected BlockState createBlockState() {
// These actually have to be explicitly called as 'new IProperty[]' - cannot simply be listed as arguments
return new ExtendedBlockState(this, new IProperty[] {UNBREAKABLE}, new IUnlistedProperty[] {RENDER_BLOCK});
}
@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof TileEntityDungeonStone && state instanceof IExtendedBlockState) { // avoid crash in case of mismatch
IExtendedBlockState extended = (IExtendedBlockState) state;
IBlockState renderState = ((TileEntityDungeonStone) te).getRenderState();
if (renderState != null) {
return extended.withProperty(RENDER_BLOCK, renderState);
}
}
return state;
}
/**
* Return the default render block state for the normal or unbreakable version
*/
public IBlockState getDefaultRenderState(boolean isUnbreakable) {
return Blocks.stone.getDefaultState().withProperty(BlockStone.VARIANT, isUnbreakable ? BlockStone.EnumType.ANDESITE_SMOOTH : BlockStone.EnumType.ANDESITE);
}
@Override
@SideOnly(Side.CLIENT)
public int colorMultiplier(IBlockAccess world, BlockPos pos, int renderPass) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof TileEntityDungeonStone) {
return ((TileEntityDungeonStone) te).getRenderState().getBlock().colorMultiplier(world, pos, renderPass);
}
return super.colorMultiplier(world, pos, renderPass);
}
@Override
@SideOnly(Side.CLIENT)
public EnumWorldBlockLayer getBlockLayer() {
// CUTOUT_MIPPED allows both grass-like blocks and solids to render perfectly fine
// TRANSLUCENT works for the above as well as ice, but results in x-ray issues and is more expensive anyway
return EnumWorldBlockLayer.CUTOUT_MIPPED;
}
@Override
@SideOnly(Side.CLIENT)
public void getSubBlocks(Item item, CreativeTabs tab, List<ItemStack> list) {
list.add(new ItemStack(item, 1, 0));
list.add(new ItemStack(item, 1, 8));
}
/**
* Always returns the same base texture, since ISmartModel will handle the actual render state
*/
@Override
@SideOnly(Side.CLIENT)
public IStateMapper getCustomStateMap() {
return new StateMapperBase() {
@Override
protected ModelResourceLocation getModelResourceLocation(IBlockState state) {
return ModelDungeonBlock.resource;
}
};
}
@Override
@SideOnly(Side.CLIENT)
public Collection<ModelResourceLocation> getDefaultResources() {
return Lists.newArrayList(ModelDungeonBlock.resource);
}
@Override
@SideOnly(Side.CLIENT)
public Class<? extends IBakedModel> getNewModel() {
return ModelDungeonBlock.class;
}
public static class UnlistedRenderBlock implements IUnlistedProperty<IBlockState>
{
@Override
public String getName() {
return "UnlistedPropertyRenderBlock";
}
@Override
public boolean isValid(IBlockState value) {
return true;
}
@Override
public Class<IBlockState> getType() {
return IBlockState.class;
}
@Override
public String valueToString(IBlockState value) {
return value.toString();
}
}
}