/**
* Copyright (c) Lambda Innovation, 2013-2016
* This file is part of the AcademyCraft mod.
* https://github.com/LambdaInnovation/AcademyCraft
* Licensed under GPLv3, see project root for more information.
*/
package cn.academy.core.entity;
import cn.academy.core.AcademyCraft;
import cn.academy.core.client.render.RenderEntityBlock;
import cn.lambdalib.annoreg.core.Registrant;
import cn.lambdalib.annoreg.mc.RegEntity;
import cn.lambdalib.s11n.network.TargetPoints;
import cn.lambdalib.s11n.network.NetworkMessage;
import cn.lambdalib.s11n.network.NetworkMessage.Listener;
import cn.lambdalib.util.entityx.EntityAdvanced;
import cn.lambdalib.util.entityx.event.CollideEvent;
import cn.lambdalib.util.entityx.event.CollideEvent.CollideHandler;
import cn.lambdalib.util.entityx.handlers.Rigidbody;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
/**
* An entity that renders block.
* @author WeAthFolD
*/
@Registrant
@RegEntity
@RegEntity.HasRender
public class EntityBlock extends EntityAdvanced {
@SideOnly(Side.CLIENT)
@RegEntity.Render
public static RenderEntityBlock renderer;
/**
* Create an EntityBlock from the block given in the coordinate.
* DOESN't set the coordinate, do it yourself!
* @return An setup entity block, or null if convert failed.
*/
public static EntityBlock convert(World world, int x, int y, int z) {
EntityBlock ret = new EntityBlock(world);
if(!ret.setBlock(world.getBlock(x, y, z), world.getBlockMetadata(x, y, z)))
return null;
ret.setTileEntity(world.getTileEntity(x, y, z));
return ret;
}
private static final int BLOCKID = 4, META = 5;
public Block block;
public int metadata = 0;
public TileEntity tileEntity;
// other
public boolean placeWhenCollide = true;
EntityPlayer player;
public float yaw, lastYaw, pitch, lastPitch;
/**
* Server ctor. We use a player parameter to forge the ItemBlock#placeBlockAt function's parameter.
*/
public EntityBlock(EntityPlayer _player) {
this(_player.worldObj);
player = _player;
}
public EntityBlock(World world) {
super(world);
Rigidbody rb = new Rigidbody();
rb.accurateCollision = true;
this.addMotionHandler(rb);
ignoreFrustumCheck = true;
}
// Additional hack for scala...
public void constructServer(EntityPlayer _player) {
player = _player;
}
// Hack...
public void setPlaceFromServer(boolean value) {
placeWhenCollide = value;
NetworkMessage.sendToAllAround(
TargetPoints.convert(this, 20),
this, "spfs", value
);
}
@Listener(channel="spfs", side={Side.CLIENT})
private void hSpfs(boolean value) {
placeWhenCollide = value;
}
@Override
public void entityInit() {
dataWatcher.addObject(BLOCKID, (short) 0);
dataWatcher.addObject(META, (byte) 0);
setSize(1, 1);
}
@Override
public void onUpdate() {
super.onUpdate();
lastYaw = yaw;
lastPitch = pitch;
if(worldObj.isRemote) {
block = Block.getBlockById(dataWatcher.getWatchableObjectShort(BLOCKID));
metadata = dataWatcher.getWatchableObjectByte(META);
} else {
if(block != null) {
dataWatcher.updateObject(BLOCKID, (short) Block.getIdFromBlock(block));
dataWatcher.updateObject(META, (byte) metadata);
if(tileEntity != null)
tileEntity.blockMetadata = metadata;
}
}
}
@Override
public void onFirstUpdate() {
this.regEventHandler(new CollideHandler() {
@Override
public void onEvent(CollideEvent event) {
if(placeWhenCollide && !worldObj.isRemote && event.result.typeOfHit == MovingObjectType.BLOCK) {
int tx = event.result.blockX,
ty = event.result.blockY,
tz = event.result.blockZ;
int iter = 10;
while (iter --> 0) {
Block hitblock = worldObj.getBlock(tx, ty, tz);
if(!hitblock.isReplaceable(worldObj, tx, ty, tz)) {
ForgeDirection dir = ForgeDirection.values()[event.result.sideHit];
tx += dir.offsetX;
ty += dir.offsetY;
tz += dir.offsetZ;
} else {
((ItemBlock) Item.getItemFromBlock(block)).placeBlockAt(
new ItemStack(block, 0, metadata), player, worldObj, tx, ty, tz, event.result.sideHit,
tx, ty, tz, metadata);
break;
}
}
setDead();
}
}
});
if(!worldObj.isRemote && tileEntity != null) {
try {
NBTTagCompound tag = new NBTTagCompound();
tileEntity.writeToNBT(tag);
NetworkMessage.sendToDimension(worldObj.provider.dimensionId, this, "sync_te",
tileEntity.getClass().getName(), tag);
} catch(Exception e) {
AcademyCraft.log.error("Error syncing te", e);
}
}
}
public boolean isAvailable() {
return block != null;
}
public void setBlock(Block _block) {
block = _block;
}
public boolean setBlock(Block _block, int _metadata) {
if(Item.getItemFromBlock(_block) == null)
return false;
block = _block;
metadata = _metadata;
return true;
}
public void fromItemStack(ItemStack stack) {
Block block = Block.getBlockFromItem(stack.getItem());
int meta = stack.getItemDamage();
setBlock(block, meta);
if(block instanceof ITileEntityProvider) {
TileEntity te = ((ITileEntityProvider)block)
.createNewTileEntity(worldObj, meta);
setTileEntity(te);
}
}
public void setTileEntity(TileEntity _te) {
tileEntity = _te;
}
public boolean shouldRender() {
return block != null;
}
@Override
public boolean shouldRenderInPass(int pass) {
return (block != null && block.getRenderBlockPass() == pass) ||
(tileEntity != null && tileEntity.shouldRenderInPass(pass));
}
@Override
protected void readEntityFromNBT(NBTTagCompound tag) {
setDead();
}
@Override
protected void writeEntityToNBT(NBTTagCompound tag) {
}
@Listener(channel="sync_te", side=Side.CLIENT)
private void hSyncTE(String className, NBTTagCompound initTag) {
try {
TileEntity te = (TileEntity) Class.forName(className).newInstance();
te.readFromNBT(initTag);
te.setWorldObj(worldObj);
tileEntity = te;
} catch(Exception e) {
AcademyCraft.log.error("Unable to sync tileEntity " + className, e);
}
}
}