/**
* Copyright (c) Lambda Innovation, 2013-2015
* 本作品版权由Lambda Innovation所有。
* http://www.li-dev.cn/
*
* This project is open-source, and it is distributed under
* the terms of GNU General Public License. You can modify
* and distribute freely as long as you follow the license.
* 本项目是一个开源项目,且遵循GNU通用公共授权协议。
* 在遵照该协议的情况下,您可以自由传播和修改。
* http://www.gnu.org/licenses/gpl.html
*/
package cn.liutils.util.helper;
import java.util.Random;
import cn.liutils.util.generic.DebugUtils;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
/**
* A entity that has its position and motion properties. used for all kinds of spacial calculations.
* @author WeAthFolD
*/
public class Motion3D {
private static final Random RNG = new Random();
public static final double OFFSET_SCALE = 0.5D;
public double vx, vy, vz; //Velocity
public double px, py, pz; //Position
public Motion3D(double pX, double pY, double pZ, double moX, double moY, double moZ) {
px = pX;
py = pY;
pz = pZ;
vx = moX;
vy = moY;
vz = moZ;
}
public Motion3D(Vec3 posVec, double moX, double moY, double moZ) {
this(posVec.xCoord, posVec.yCoord, posVec.zCoord, moX, moY, moZ);
}
public Motion3D(Vec3 pos, Vec3 vel) {
this(pos, vel.xCoord, vel.yCoord, vel.zCoord);
}
public Motion3D(double x, double y, double z) {
px = x;
py = y;
pz = z;
}
public Motion3D() {
this(0, 0, 0, 0, 0, 0);
}
/**
* Create an Motion3D based on its position and moving direction.
*/
public Motion3D(Entity ent) {
this(ent, 0, false);
}
/**
* @see cn.liutils.api.util.Motion3D(Entity, int, boolean)
* @param ent entity
* @param dirFlag false:use moving direction; true:use head-looking direction
*/
public Motion3D(Entity ent, boolean dirFlag) {
this(ent, 0, dirFlag);
}
/**
* Create an Motion3D from an entity, selectible offset.
* @param entity
* @param offset direction offset
* @param dirFlag false:use moving direction; true:use head-looking direction
*/
public Motion3D(Entity entity, double offset, boolean dirFlag) {
init(entity, offset, dirFlag);
}
@Override
public Motion3D clone() {
Motion3D ret = new Motion3D();
ret.setFrom(this);
return ret;
}
public void setFrom(Motion3D ano) {
px = ano.px;
py = ano.py;
pz = ano.pz;
vx = ano.vx;
vy = ano.vy;
vz = ano.vz;
}
/**
* Reset the pos and motion data to the data of entity passed in
* @param entity
* @param offset
* @param dirFlag true: use head facing direction; flase: use motion
*/
public void init(Entity entity, double offset, boolean dirFlag) {
this.px = entity.posX;
this.py = entity.posY + entity.getEyeHeight();
this.pz = entity.posZ;
if (dirFlag) {
float rotationYaw = (float) (
(entity instanceof EntityLivingBase ? entity.getRotationYawHead() : entity.rotationYaw)
+ 2 * (RNG.nextFloat() - 0.5F) * offset);
float rotationPitch = (float) (entity.rotationPitch + (RNG.nextFloat() - 0.5F) * offset);
fromRotation(rotationYaw, rotationPitch);
} else {
vx = entity.motionX;
vy = entity.motionY;
vz = entity.motionZ;
setMotionOffset(offset);
}
this.normalize();
if(entity instanceof EntityPlayer && entity.worldObj.isRemote) {
checkClientOffset((EntityPlayer) entity);
}
}
@SideOnly(Side.CLIENT)
private void checkClientOffset(EntityPlayer entity) {
if(Minecraft.getMinecraft().thePlayer != entity)
px += 1.6;
}
public Motion3D fromRotation(float rotationYaw, float rotationPitch) {
this.vx = -MathHelper.sin(rotationYaw / 180.0F
* (float) Math.PI)
* MathHelper.cos(rotationPitch / 180.0F
* (float) Math.PI);
this.vz = MathHelper.cos(rotationYaw / 180.0F
* (float) Math.PI)
* MathHelper.cos(rotationPitch / 180.0F
* (float) Math.PI);
this.vy = -MathHelper.sin((rotationPitch) / 180.0F * (float) Math.PI);
return this;
}
public float getRotationYaw() {
return -(float)(Math.atan2(vx, vz) * 180.0D / Math.PI);
}
public float getRotationYawRadians() {
return -(float)(Math.atan2(vx, vz));
}
public float getRotationPitch() {
return -(float)(Math.atan2(vy, Math.sqrt(vx * vx + vz * vz)) * 180.0D / Math.PI);
}
public float getRotationPitchRadians() {
return -(float)(Math.atan2(vy, Math.sqrt(vx * vx + vz * vz)));
}
public Motion3D setPosition(double x, double y, double z) {
px = x;
py = y;
pz = z;
return this;
}
public Motion3D setMotion(double x, double y, double z) {
vx = x;
vy = y;
vz = z;
return this;
}
public Motion3D multiplyMotionBy(double d) {
vx *= d;
vy *= d;
vz *= d;
return this;
}
/**
* Add a 3-dimension randomized offset for the motion vec.
* @param par1
* @return
*/
public Motion3D setMotionOffset(double par1) {
this.vx += (RNG.nextDouble() - .5) * par1 * OFFSET_SCALE;
this.vy += (RNG.nextDouble() - .5) * par1 * OFFSET_SCALE;
this.vz += (RNG.nextDouble() - .5) * par1 * OFFSET_SCALE;
return this;
}
/*
* Apply the position and rotation data to the entity.
* @param mo
* @param e
*/
public void applyToEntity(Entity e) {
e.setPosition(this.px, this.py, this.pz);
e.motionX = vx;
e.motionY = vy;
e.motionZ = vz;
e.prevRotationYaw = e.rotationYaw = getRotationYaw();
e.prevRotationPitch = e.rotationPitch = getRotationPitch();
}
/**
* Move this motion3D towards motion vec direction. Doesn't copy the class.
* @param step
* @return this
*/
public Motion3D move(double step) {
px += vx * step;
py += vy * step;
pz += vz * step;
return this;
}
/**
* Normalize the motion vector.
* @return this
*/
public Motion3D normalize() {
double z = Math.sqrt(vx * vx + vy * vy + vz * vz);
vx /= z;
vy /= z;
vz /= z;
return this;
}
public Vec3 getPosVec() {
return Vec3.createVectorHelper(px, py, pz);
}
public Vec3 getMotionVec() {
return Vec3.createVectorHelper(vx, vy, vz);
}
@Override
public String toString() {
return "[ Motion3D POS" + DebugUtils.formatArray(px, py, pz) + "MOTION" + DebugUtils.formatArray(vx, vy, vz) + " ]";
}
}