package net.kennux.cubicworld.voxel;
import java.lang.reflect.InvocationTargetException;
import net.kennux.cubicworld.CubicWorldConfiguration;
import net.kennux.cubicworld.inventory.BlockInventory;
import net.kennux.cubicworld.plugins.baseplugin.BasePlugin;
import net.kennux.cubicworld.serialization.BitReader;
import net.kennux.cubicworld.serialization.BitWriter;
import net.kennux.cubicworld.util.ConsoleHelper;
import net.kennux.cubicworld.voxel.handlers.IVoxelTileEntityHandler;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.math.collision.BoundingBox;
/**
* The voxel data class which gets used for holding data which every voxel has.
* The voxelchunk uses it to manage it's voxel data information.
*
* @author KennuX
*
*/
public class VoxelData
{
/**
* Constructs a voxeldata instance for the given type id.
* if type id is < 0 it will return null.
*
* @param typeId
* @return
*/
public static VoxelData construct(short typeId)
{
if (typeId < 0)
return null;
VoxelData data = new VoxelData();
data.voxelType = VoxelEngine.getVoxelType(typeId);
data.rotation = 0;
if (data.voxelType.getInventorySize() > 0)
{
data.blockInventory = new BlockInventory(data.voxelType.getInventorySize());
data.blockInventory.setFilterRuleSet(data.voxelType.getFilterRuleSet());
data.blockInventory.addItemsToStack(1, 10, BasePlugin.itemCoalId);
}
// Tile entity instantiation
if (data.voxelType.isTileEntity())
{
data.tileEntity = data.voxelType.getTileEntityHandlerFactory().newInstance();
}
return data;
}
public static VoxelData construct(short typeId, byte rotation)
{
// Is it < 0?
if (typeId < 0)
return null;
VoxelData d = construct(typeId);
d.rotation = rotation;
return d;
}
/**
* Deserializes a voxel data object from the given reader.
*
* @param reader
* @return
*/
public static VoxelData deserialize(BitReader reader)
{
short voxelId = reader.readShort();
byte rotation = reader.readByte();
// Filter invalid block data
if (voxelId == -1 || rotation == -1)
return new VoxelData();
VoxelData v = VoxelData.construct(voxelId);
v.rotation = rotation;
if (v.voxelType.getInventorySize() > 0)
{
v.blockInventory.deserializeInventory(reader);
}
if (v.tileEntity != null)
{
v.tileEntity.deserialize(reader);
}
return v;
}
/**
* Serializes the given voxel data object to the given writer.
*
* @return
*/
public static void serialize(VoxelData voxelDataObject, BitWriter writer)
{
if (voxelDataObject == null || voxelDataObject.voxelType == null)
{
writer.writeShort((short) -1);
writer.writeByte((byte) 0);
}
else
{
writer.writeShort(voxelDataObject.voxelType.voxelId);
writer.writeByte(voxelDataObject.rotation);
// Write inventory
if (voxelDataObject.voxelType.getInventorySize() > 0)
{
voxelDataObject.blockInventory.serializeInventory(writer);
}
// Write data model
if (voxelDataObject.tileEntity != null)
{
voxelDataObject.tileEntity.serialize(writer);
}
}
}
/**
* The footstep sound used if no special one was specified.
* Gets loaded in the bootstrap's loadSounds().
*/
public static Sound standardFootstepSound;
/**
* The voxel type of this voxel data.
*/
public VoxelType voxelType;
/**
* The rotation of this voxel data.
*/
public byte rotation = 0;
/**
* This voxeldata's light level.
*/
public byte lightLevel;
/**
* The voxel data model.
*/
public IVoxelTileEntityHandler tileEntity;
/**
* Gets created in the construct() methods.
*/
public BoundingBox boundingBox;
/**
* <pre>
* Is null if this block does not have an inventory.
* Otherwise it contains it's block inventory instance.
*
* When accessing the inventory you need to call the setVoxel method of the voxel world in order to keep things synchron.
* Example code:
*
* int itemId = 1;
* VoxelData v = this.voxelWorld.getVoxel(x,y,z);
* v.blockInventory.setItemStackInSlot(new ItemStack(itemId, 10), 0);
* this.voxelWorld.setVoxel(x,y,z,v);
*
* The call to set voxel will make the server send out the voxel update packet.
* </pre>
*/
public BlockInventory blockInventory;
/**
* The current render state.
* This is a byte, because there shouldnt be more than 127 render states. never.
*/
private byte renderStateId = 0;
/**
* @return the renderStateId
*/
public VoxelRenderState getRenderState()
{
return this.voxelType.getRenderState(this.renderStateId);
}
/**
* @param renderStateId
* the renderStateId to set
*/
public int getRenderStateId()
{
return this.renderStateId;
}
/**
* <pre>
* Transforms the given voxel face.
* The face is the face detected by raycasting.
* If the block got rotated, the textures on the left side may not be on the left side because of the uv flip.
* This function transforms a worldspace facing to the uv textures facing.
* </pre>
*
* @param facing
* @return
*/
public VoxelFace getTransformedFacing(VoxelFace facing)
{
return VoxelChunk.ROTATION_MAPPINGS[this.rotation][facing.getValue()];
}
/**
* @param renderStateId
* the renderStateId to set
*/
public void setRenderStateId(int renderStateId)
{
this.renderStateId = (byte)renderStateId;
}
}