package net.kennux.cubicworld.entity;
import net.kennux.cubicworld.CubicWorld;
import net.kennux.cubicworld.CubicWorldServer;
import net.kennux.cubicworld.item.ItemSystem;
import net.kennux.cubicworld.item.ItemType;
import net.kennux.cubicworld.networking.CubicWorldServerClient;
import net.kennux.cubicworld.serialization.BitReader;
import net.kennux.cubicworld.serialization.BitWriter;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.decals.Decal;
import com.badlogic.gdx.graphics.g3d.decals.DecalBatch;
import com.badlogic.gdx.math.Vector3;
/**
* <pre>
* The item entity implementation will get used for syncing and rendering of iems in the world.
* </pre>
*
* @author KennuX
*
*/
public class ItemEntity extends ACharacterEntity
{
private ItemType itemType;
private Decal itemDecal;
/**
* The milliseconds stamp when this item was initialized
*/
private long started;
/**
*
*/
private int framesPassedSinceLastUserCheck = 0;
public ItemEntity()
{
super();
this.started = System.currentTimeMillis();
}
public ItemEntity(int itemId)
{
this();
this.itemType = ItemSystem.getItemType(itemId);
}
/**
* <pre>
* Reads serialized data obtained from a server packet.
* This implementation will just read position and eulerAngles as vector3
* (in this order) from the stream.
* Override this method if you want to extend the synchronization.
* </pre>
*
* @param reader
*/
public void deserialize(BitReader reader)
{
this.setPosition(reader.readVector3());
}
/**
* Deserializes this entity's initial state.
*
* @see AEntity#deserialize(BitReader)
* @param reader
*/
public void deserializeInitial(BitReader reader)
{
this.itemType = ItemSystem.getItemType(reader.readInt());
this.deserialize(reader);
}
@Override
protected float getCharacterHeight()
{
return 1;
}
@Override
public void init()
{
this.voxelWorld = this.master.getWorld();
this.setEntityName("Item");
}
@Override
public void render(Camera camera, ModelBatch modelBatch, DecalBatch decalBatch, SpriteBatch spriteBatch, BitmapFont bitmapFont)
{
// Only if this item already got initialized
if (this.itemType != null)
{
if (this.itemType.getItemModel() != null)
{
// Model rendering
// TODO
}
else
{
// Billboard rendering
if (this.itemDecal == null)
{
this.itemDecal = Decal.newDecal(this.itemType.getItemTextureRegion(), true);
this.itemDecal.setWidth(1.0f);
this.itemDecal.setHeight(1.0f);
}
// Offset + 0.5f + random
Vector3 renderPos = new Vector3(this.position);
renderPos.y += 0.5f + (0.1f * (float) Math.sin((System.currentTimeMillis() - this.started) / 200.0f));
// Calculate direction from item to camera
Vector3 dir = new Vector3(renderPos).sub(camera.position).nor();
this.itemDecal.setRotation(dir, Vector3.Y);
this.itemDecal.setPosition(renderPos);
decalBatch.add(this.itemDecal);
}
}
}
/**
* <pre>
* Serializes the entity.
* This implementation will just write position and eulerAngles as vector3
* (in this order) to the stream.
* Override this method if you want to extend the synchronization.
* </pre>
*
* @param writer
*/
public void serialize(BitWriter writer)
{
writer.writeVector3(this.position);
}
/**
* Serializes this entity's initial state.
*
* @see AEntity#serialize(BitWriter)
* @param writer
*/
public void serializeInitial(BitWriter writer)
{
writer.writeInt(this.itemType.getItemId());
this.serialize(writer);
}
@Override
public void update()
{
super.update();
if (this.master.isServer())
{
if (this.framesPassedSinceLastUserCheck >= 40)
{
// Check if there is a player around this item entity.
CubicWorldServer server = CubicWorld.getServer();
CubicWorldServerClient playerNearThisItem = null;
synchronized (server.clientsLockObject)
{
for (CubicWorldServerClient serverClient : server.clients)
{
// Check if nearby
if (serverClient != null && new Vector3(serverClient.playerEntity.getPosition()).sub(this.getPosition()).len() < 1.5f)
{
// Nearby!
playerNearThisItem = serverClient;
break;
}
}
}
if (playerNearThisItem != null)
{
// Pickup!
int slotId = playerNearThisItem.playerEntity.playerInventory.getFirstStackForItemTypeWithSpace(this.itemType.getItemId());
// Destroy if pickup was successfull
if (playerNearThisItem.playerEntity.playerInventory.addItemsToStack(slotId, 1))
{
server.destroyEntity(this);
this.master.remove(this.getEntityId());
}
}
this.framesPassedSinceLastUserCheck = 0;
}
else
{
this.framesPassedSinceLastUserCheck++;
}
}
}
}