Java tutorial
package smpships.entity; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import java.util.UUID; import smpships.SMPships; import smpships.Utils; import net.minecraft.entity.IEntityMultiPart; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.world.World; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataOutput; import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; /** * An entity that looks and feels like a block, that is NOT the control block * (for that see {@code ControlBlockEntity}). These are the children entity, * and have a {@code ControlBlockEntity} as a parent. Note must implement * IEntityAdditionalSpawnData, because Minecraft calls constructor #1, * which sets all my variables in this class to 0 or null. so make sure all * variables are saved and loaded in read/writeSpawnData() down below. * <p> * trying to replace bounding box with anything at all results in no collisions * <p> * special block entities (e.g. chests) would probably best be done as a subclass of this, for full functionality * <p> * March 2013<br> * Released under the <a href=http://www.gnu.org/copyleft/gpl.html>GNU General Public License</a> * * @author Grumdot * @author MineS1m0n * @see EntityShipBlock */ public class EntityBlock extends Entity implements IEntityAdditionalSpawnData { public EntityShipBlock parent; public int xOff; // offset from parent public int yOff; public int zOff; public int blockID; public int metadata; public EntityBlock(World w) {//constructor #1, not used by me but often called by Minecraft super(w); preventEntitySpawning = true; setSize(Utils.blockEntityWidth, Utils.blockEntityWidth); //yOffset = height / 2.0F; isImmuneToFire = true; } public EntityBlock(World w, double x, double y, double z, int blockID, int metadata, EntityShipBlock ship) {//constructor #2 used by me this(w); this.parent = ship; this.blockID = blockID; this.metadata = metadata; setPosition(x, y, z); //note this also creates bounding box (using height and width) xOff = (int) (posX - ship.posX); yOff = (int) (posY - ship.posY); zOff = (int) (posZ - ship.posZ); } @Override protected boolean canTriggerWalking() { return false; } @Override public boolean isEntityInvulnerable() { return true; } @Override public float getShadowSize() { return 0.0F; } @Override public ItemStack getPickedResult(MovingObjectPosition target) { return new ItemStack(Block.blocksList[blockID]); } // children do nothing (at least they don't move themselves) parents will do all calculations an movements - part of the minimization of server-client network traffic @Override protected void entityInit() { } @Override public String toString() { return "BlockEntity [ship=" + parent + ", xOff=" + xOff + ", yOff=" + yOff + ", zOff=" + zOff + ", blockId=" + blockID + ", meta=" + metadata + "]"; } // ####################### // collision related stuff // ####################### // Overridden to collide with all entities except player @Override public boolean canBeCollidedWith() { return true; } @Override public AxisAlignedBB getCollisionBox(Entity var1) { // this does NOT appear to be needed to collide with player. other entities only? return var1.boundingBox; // entity default is null. Note bounding box is created when Entity.setPosition() is called } @Override public AxisAlignedBB getBoundingBox() { //This is the only essential one for player collision. return this.boundingBox; // entity default is null. Note bounding box is created when Entity.setPosition() is called } public void applyEntityCollision(Entity par1Entity) { //pushes two entities away from each other. I've overridden so the ship doesn't get pushed. if (par1Entity != parent && par1Entity.riddenByEntity != this && par1Entity.ridingEntity != this) { double var2 = par1Entity.posX - this.posX; double var4 = par1Entity.posZ - this.posZ; double var6 = MathHelper.abs_max(var2, var4); if (var6 >= 0.009999999776482582D) { var6 = (double) MathHelper.sqrt_double(var6); var2 /= var6; var4 /= var6; double var8 = 1.0D / var6; if (var8 > 1.0D) var8 = 1.0D; var2 *= var8; var4 *= var8; var2 *= 0.05000000074505806D; var4 *= 0.05000000074505806D; var2 *= (double) (1.0F - this.entityCollisionReduction); var4 *= (double) (1.0F - this.entityCollisionReduction); //this.addVelocity(-var2, 0.0D, -var4); //removed --- untested, no idea if this works par1Entity.addVelocity(var2, 0.0D, var4); } } } // ################################ // reading and writing data to disk // ################################ @Override protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) { // do nothing, leave it to parent readControlBlockEntityFromNBT(par1NBTTagCompound); } @Override protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) { // don't write kids to disk - have parent kill them all and recreate them on read writeControlBlockEntityToNBT(par1NBTTagCompound); } protected void writeControlBlockEntityToNBT(NBTTagCompound par1NBTTagCompound) { } //for ControlBlockEntitys extra fields - mc uses this style so I followed suit... protected void readControlBlockEntityFromNBT(NBTTagCompound par1NBTTagCompound) { } // ################################## // IEntityAdditionalSpawnData methods // ################################## // without this stuff, all variables in class get reset to 0/null by minecraft calling constructor #1 (on client) /* * final note re. these two methods (later than all other notes here, above or below) * * these should do nothing for children - the control block recreates all children on both client and server anyway... * * but their code here is needed for parents (never got round to moving it to ControlBlockEntity) * */ @Override public void writeSpawnData(ByteArrayDataOutput data) { //child (all) entities get spawned on server only, so need to be able to pass this data to their client copies data.writeInt(blockID); data.writeInt(metadata); data.writeInt(xOff); data.writeInt(yOff); data.writeInt(zOff); writeControlBlockSpawnData(data); } @Override public void readSpawnData(ByteArrayDataInput data) { blockID = data.readInt(); metadata = data.readInt(); xOff = data.readInt(); yOff = data.readInt(); zOff = data.readInt(); readControlBlockSpawnData(data); } protected void writeControlBlockSpawnData(ByteArrayDataOutput data) { } //for ControlBlockEntitys extra fields protected void readControlBlockSpawnData(ByteArrayDataInput data) { } } // end of class