package choonster.testmod3.block;
import choonster.testmod3.TestMod3;
import choonster.testmod3.util.Constants;
import net.minecraft.block.BlockSlab;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemSlab;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.NonNullList;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;
/**
* Base class for this mod's slab blocks.
*
* @param <VARIANT> The variant type
* @param <VARIANTS> The variant collection type
* @param <SLAB> The slab type
* @author Choonster
*/
public abstract class BlockSlabTestMod3<
VARIANT extends Enum<VARIANT> & IStringSerializable,
VARIANTS extends Iterable<VARIANT> & IStringSerializable,
SLAB extends BlockSlabTestMod3<VARIANT, VARIANTS, SLAB>
> extends BlockSlab {
/**
* The group this slab belongs to
*/
protected final SlabGroup<VARIANT, VARIANTS, SLAB> slabGroup;
/**
* The variants of this slab
*/
protected final VARIANTS variants;
/**
* Create a slab block.
*
* @param material The Material of this slab
* @param slabGroup The group this slab belongs to
* @param variants The variants of this slab
*/
public BlockSlabTestMod3(Material material, SlabGroup<VARIANT, VARIANTS, SLAB> slabGroup, VARIANTS variants) {
super(material);
this.slabGroup = slabGroup;
this.variants = variants;
// Vanilla sets this for anything that extends BlockSlab in Block.registerBlocks,
// but this is run before mods are loaded; so we need to set it manually.
// Thanks to HappyKiller1O1 for pointing out this field to me:
// http://www.minecraftforge.net/forum/index.php/topic,36125.msg190252.html#msg190252
this.useNeighborBrightness = true;
String name = slabGroup.groupName + "_" + variants.getName();
if (isDouble()) {
name = "double_" + name;
}
setRegistryName(TestMod3.MODID, name);
setUnlocalizedName(Constants.RESOURCE_PREFIX + slabGroup.groupName);
IBlockState iblockstate = this.blockState.getBaseState();
if (!isDouble()) {
iblockstate = iblockstate.withProperty(HALF, BlockSlab.EnumBlockHalf.BOTTOM);
}
final Optional<VARIANT> defaultVariant = getVariantProperty().getAllowedValues().stream().findFirst();
if (defaultVariant.isPresent()) {
iblockstate = iblockstate.withProperty(getVariantProperty(), defaultVariant.get());
}
setDefaultState(iblockstate);
setCreativeTab(TestMod3.creativeTab);
}
/**
* Get the metadata value for the specified variant
*
* @param variant The variant
* @return The metadata value
*/
public abstract int getMetadata(VARIANT variant);
/**
* Get the variant for the specified metadata value
*
* @param meta The metadata value
* @return The variant
*/
protected abstract VARIANT getVariant(int meta);
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune) {
return slabGroup.item;
}
@Override
public abstract IProperty<VARIANT> getVariantProperty();
@SideOnly(Side.CLIENT)
@Override
public void getSubBlocks(Item item, CreativeTabs tab, NonNullList<ItemStack> list) {
list.addAll(getVariantProperty().getAllowedValues().stream()
.map(variant -> new ItemStack(item, 1, getMetadata(variant)))
.collect(Collectors.toList()));
}
@SuppressWarnings("deprecation")
@Override
public IBlockState getStateFromMeta(int meta) {
final VARIANT variant = getVariant(meta & 7);
IBlockState state = this.getDefaultState().withProperty(getVariantProperty(), variant);
if (!this.isDouble()) {
state = state.withProperty(HALF, (meta & 8) == 0 ? EnumBlockHalf.BOTTOM : EnumBlockHalf.TOP);
}
return state;
}
@Override
public int getMetaFromState(IBlockState state) {
int meta = getMetadata(state.getValue(getVariantProperty()));
if (!this.isDouble() && state.getValue(HALF) == EnumBlockHalf.TOP) {
meta |= 8;
}
return meta;
}
@Override
protected BlockStateContainer createBlockState() {
return isDouble() ? new BlockStateContainer(this, getVariantProperty()) : new BlockStateContainer(this, HALF, getVariantProperty());
}
@Override
public int damageDropped(IBlockState state) {
return getMetadata(state.getValue(getVariantProperty()));
}
/**
* A group consisting of a single and a double slab.
*
* @param <VARIANT> The variant type
* @param <VARIANTS> The variant collection type
* @param <SLAB> The slab type
*/
public static abstract class SlabGroup<
VARIANT extends Enum<VARIANT> & IStringSerializable,
VARIANTS extends Iterable<VARIANT> & IStringSerializable,
SLAB extends BlockSlabTestMod3<VARIANT, VARIANTS, SLAB>
> {
public final SLAB singleSlab;
public final SLAB doubleSlab;
public final String groupName;
public final ItemSlab item;
/**
* Create a slab group.
*
* @param groupName The group's name
* @param material The Material of the slabs
* @param variants The variants of the slabs
*/
public SlabGroup(String groupName, Material material, VARIANTS variants) {
this.groupName = groupName;
this.singleSlab = createSlab(material, false, variants);
this.doubleSlab = createSlab(material, true, variants);
this.item = new ItemSlab(singleSlab, singleSlab, doubleSlab);
}
/**
* Create a slab block.
*
* @param material The Material
* @param isDouble Is this a double slab?
* @param variants The variants
* @return The slab block
*/
public abstract SLAB createSlab(Material material, boolean isDouble, VARIANTS variants);
}
}