package net.CyanWool.entity;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import net.CyanWool.api.CyanWool;
import net.CyanWool.api.Server;
import net.CyanWool.api.entity.Entity;
import net.CyanWool.api.entity.EntityType;
import net.CyanWool.api.entity.component.ComponentManager;
import net.CyanWool.api.entity.component.MovementComponent;
import net.CyanWool.api.entity.component.TransportComponent;
import net.CyanWool.api.entity.meta.MetaHelper;
import net.CyanWool.api.entity.meta.MetadataMap;
import net.CyanWool.api.world.Chunk;
import net.CyanWool.api.world.Location;
import net.CyanWool.api.world.World;
import net.CyanWool.entity.meta.CyanMetadataMap;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerDestroyEntitiesPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket;
import org.spacehq.packetlib.packet.Packet;
public abstract class CyanEntity implements Entity {
private boolean moved;
private boolean teleported;
private boolean rotated;
private Location location;
private Location prevLoc;
protected boolean isAlive;
private int fireTicks;
private int entityId;
private boolean invisible;
private boolean onGround;
private int livedTicks;
private ComponentManager component;
// TODO: Metadata
protected MetadataMap metadata;
private boolean moveable;
public CyanEntity(Location location) {
this.isAlive = true;
this.prevLoc = location.clone();
this.location = location.clone();
this.component = new ComponentManager(this);
this.metadata = new CyanMetadataMap();
getComponentManager().addComponent(new MovementComponent(this));
getComponentManager().addComponent(new TransportComponent(this));
// getServer().getEntityManager().register(this);
getWorld().getServer().getEntityManager().register(this);
initMetadata();
// TODO
}
protected void initMetadata() {
// TODO: Metadata
// Information about metadata:
// http://wiki.vg/Entities#Entity_Metadata_Format
getMetadata().setMetadata(0, (byte) 0);
getMetadata().setMetadata(1, (short) 0);
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.ON_FIRE, this.fireTicks > 0);
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.SNEAKING, isSneaking());
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.SPRINTING, isSprinting());
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.ARM_UP, false);// Eating,
// drinking,
// blocking
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.INVISIBLE, this.invisible);
}
@Override
public Location getLocation() {
return location;
}
@Override
public World getWorld() {
return location.getWorld();
}
@Override
public void teleport(Location location) {
this.teleported = true;
this.location = location;
}
@Override
public boolean isAlive() {
return isAlive;
}
@Override
public boolean isBurning() {
return getFireTicks() > 0;
}
@Override
public boolean isImmuneToFire() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isInvisible() {
return invisible;
}
@Override
public boolean isSneaking() {
if (getComponentManager().hasComponent("movement")) {
MovementComponent component = (MovementComponent) getComponentManager().getComponent("movement");
return component.isSneaking();
}
return false;
}
@Override
public boolean isSprinting() {
if (getComponentManager().hasComponent("movement")) {
MovementComponent component = (MovementComponent) getComponentManager().getComponent("movement");
return component.isSprinting();
}
return false;
}
@Override
public boolean isWet() {
return false; // TODO
}
@Override
public boolean onGround() {
return onGround;
}
@Override
public void kill() {
// TODO damage 100500
this.isAlive = false;
getServer().getEntityManager().unregister(this);
}
@Override
public void setInvisible(boolean flag) {
this.invisible = flag;
}
@Override
public void onTick() {
// Maybe...
if (!isAlive) {
ServerDestroyEntitiesPacket packet = new ServerDestroyEntitiesPacket(getEntityID());
getServer().getNetworkServer().sendPacketDistance(getLocation(), packet, 32); // Test
getServer().getEntityManager().unregister(this);
return;
}
if (moveable) {
if (!prevLoc.equals(location)) {
if (prevLoc.getBlockX() != location.getBlockX() || prevLoc.getBlockY() != location.getBlockY() || prevLoc.getBlockZ() != location.getBlockZ()) {
this.moved = true;
}
if (prevLoc.getPitch() != location.getPitch() || prevLoc.getYaw() != location.getYaw()) {
this.rotated = true;
}
this.prevLoc = location;
getServer().getEntityManager().moveToOtherLocation(this, location);
}
} else {
teleport(prevLoc);
}
if (fireTicks > 0) {
fireTicks--;
}
getMetadata().setBit(MetaHelper.STATUS, MetaHelper.StatusFlags.ON_FIRE, this.fireTicks > 0);
if (livedTicks > 0) {
livedTicks++;
}
getComponentManager().onUpdateComponents();
// TODO
}
@Override
public int getFireTicks() {
return fireTicks;
}
@Override
public void setFireTicks(int fireTicks) {
this.fireTicks = fireTicks;
}
@Override
public EntityType getEntityType() {
return EntityType.NONE;
}
@Override
public int getEntityID() {
return entityId;
}
@Override
public int getLivedTicks() {
return livedTicks;
}
@Override
public void setEntityID(int id) {
this.entityId = id;
}
@Override
public ComponentManager getComponentManager() {
return component;
}
@Override
public MetadataMap getMetadata() {
return metadata;
}
@Override
public boolean isMoveable() {
return moveable;
}
@Override
public void setMoveable(boolean flag) {
this.moveable = flag;
}
@Override
public Chunk getChunk() {
return getLocation().getChunk();
}
@Override
public void setOnGround(boolean onGround) {
this.onGround = onGround;
}
@Override
public void setSneaking(boolean flag) {
MovementComponent component = (MovementComponent) getComponentManager().getComponent("movement");
component.setSneaking(flag);
}
@Override
public void setSprinting(boolean flag) {
MovementComponent component = (MovementComponent) getComponentManager().getComponent("movement");
component.setSprinting(flag);
}
@Override
public void setPassenger(Entity entity) {
TransportComponent component = (TransportComponent) getComponentManager().getComponent("transport");
component.setPassenger(entity);
}
@Override
public Entity getPassenger() {
TransportComponent component = (TransportComponent) getComponentManager().getComponent("transport");
return component.getPassenger();
}
@Override
public Entity getVehicle() {
TransportComponent component = (TransportComponent) getComponentManager().getComponent("transport");
return component.getVehicle();
}
@Override
public void setVehicle(Entity entity) {
TransportComponent component = (TransportComponent) getComponentManager().getComponent("transport");
component.setVehicle(entity);
}
@Override
public boolean canSeeEntity(Entity entity) {
return canSeeLocation(entity.getLocation());
}
@Override
public boolean canSeeLocation(Location loc) {
double dx = Math.abs(getLocation().getX() - loc.getX());
double dz = Math.abs(getLocation().getZ() - loc.getZ());
return loc.getWorld() == getWorld() && dx <= (CyanWool.getServerConfiguration().getViewDistance() * 16) && dz <= (CyanWool.getServerConfiguration().getViewDistance() * 256);
}
// Not from API
public List<Packet> getUpdatePackets() {
// From Glowstone. Thanks dudes :D
List<Packet> list = new CopyOnWriteArrayList<Packet>();
double moveX = getLocation().getX() - prevLoc.getX();
double moveY = getLocation().getY() - prevLoc.getY();
double moveZ = getLocation().getZ() - prevLoc.getZ();
if (teleported || teleported && moved) {
list.add(new ServerEntityTeleportPacket(getEntityID(), getLocation().getX(), getLocation().getY(), getLocation().getZ(), getLocation().getYaw(), getLocation().getPitch(), onGround()));
this.teleported = false;
this.moved = false;
} else if (moved && rotated) {
list.add(new ServerEntityPositionRotationPacket(getEntityID(), moveX, moveY, moveZ, getLocation().getYaw(), getLocation().getPitch(), onGround()));
this.moved = false;
this.rotated = false;
} else if (moved) {
list.add(new ServerEntityPositionPacket(getEntityID(), moveX, moveY, moveZ, onGround()));
this.moved = false;
} else if (rotated) {
list.add(new ServerEntityRotationPacket(getEntityID(), getLocation().getYaw(), getLocation().getPitch(), onGround()));
this.rotated = false;
}
// TODO: Head update
// list.add(new ServerEntityHeadLookPacket(getEntityID(),
// getLocation().getYaw()));
// TODO: Metadata
list.add(new ServerEntityMetadataPacket(getEntityID(), ((CyanMetadataMap) metadata).getMetaArray()));
return list;
}
// for others entities
public abstract List<Packet> getSpawnPackets();
@Override
public Server getServer() {
return CyanWool.getServer();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + entityId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof CyanEntity)) {
return false;
}
CyanEntity other = (CyanEntity) obj;
if (entityId != other.entityId) {
return false;
}
return true;
}
}